From 547ce943d46ebf09dbd311d6fbf3896141df0a6c Mon Sep 17 00:00:00 2001
From: jakubs <jakubs>
Date: Mon, 24 Jun 2013 13:10:55 +0000
Subject: [PATCH] SP-727 BIS-462 update of role assignment was not visible by
 the grantee in UI

SVN: 29442
---
 .../generic/server/AbstractCommonServer.java  |  3 +-
 .../generic/server/AbstractServer.java        | 52 +++++-----
 .../openbis/generic/server/CommonServer.java  | 25 +++--
 .../server/IOpenBisSessionManager.java        | 29 ++++++
 .../generic/server/OpenBisSessionManager.java | 70 ++++++++++++++
 .../server/ServiceForDataStoreServer.java     | 11 ++-
 .../generic/server/TrackingServer.java        |  5 +-
 .../v1/GeneralInformationChangingService.java |  4 +-
 .../api/v1/GeneralInformationService.java     |  4 +-
 .../plugin/demo/server/DemoServer.java        |  4 +-
 .../plugin/generic/server/GenericServer.java  | 10 +-
 .../plugin/query/server/QueryServer.java      |  4 +-
 .../query/server/api/v1/QueryApiServer.java   |  5 +-
 .../source/java/genericApplicationContext.xml |  2 +-
 .../generic/server/AbstractServerTest.java    |  9 +-
 .../generic/server/CommonServerTest.java      | 94 +++++++++++++++++--
 .../generic/server/ETLServiceTest.java        | 64 ++++++++++---
 .../shared/AbstractServerTestCase.java        | 14 ++-
 .../openbis/systemtest/CommonServerTest.java  | 76 +++++++++++++++
 19 files changed, 393 insertions(+), 92 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/IOpenBisSessionManager.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/OpenBisSessionManager.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractCommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractCommonServer.java
index a926344e7ca..66154b3c882 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractCommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractCommonServer.java
@@ -22,7 +22,6 @@ import java.util.List;
 import org.apache.commons.lang.StringUtils;
 
 import ch.systemsx.cisd.authentication.IAuthenticationService;
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.authentication.Principal;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager;
@@ -45,7 +44,7 @@ abstract class AbstractCommonServer<T extends IServer> extends AbstractServer<T>
     protected final ICommonBusinessObjectFactory businessObjectFactory;
 
     public AbstractCommonServer(IAuthenticationService authenticationService,
-            ISessionManager<Session> sessionManager, IDAOFactory daoFactory,
+            IOpenBisSessionManager sessionManager, IDAOFactory daoFactory,
             IPropertiesBatchManager propertiesBatchManager,
             ICommonBusinessObjectFactory businessObjectFactory)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java
index 21af3da8cc4..bed7f80bc96 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/AbstractServer.java
@@ -141,7 +141,7 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp
     private IDataSetTypeSlaveServerPlugin dataSetTypeSlaveServerPlugin;
 
     @Resource(name = ComponentNames.SESSION_MANAGER)
-    protected ISessionManager<Session> sessionManager;
+    protected IOpenBisSessionManager sessionManager;
 
     @Resource(name = ComponentNames.DISPLAY_SETTINGS_PROVIDER)
     protected DisplaySettingsProvider displaySettingsProvider;
@@ -174,7 +174,7 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp
                 IServer.class.getSimpleName(), getClass().getName()));
     }
 
-    protected AbstractServer(final ISessionManager<Session> sessionManager,
+    protected AbstractServer(final IOpenBisSessionManager sessionManager,
             final IDAOFactory daoFactory, IPropertiesBatchManager propertiesBatchManager)
     {
         this();
@@ -184,7 +184,7 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp
     }
 
     // For testing purpose.
-    protected AbstractServer(final ISessionManager<Session> sessionManager,
+    protected AbstractServer(final IOpenBisSessionManager sessionManager,
             final IDAOFactory daoFactory, IPropertiesBatchManager propertiesBatchManager,
             final ISampleTypeSlaveServerPlugin sampleTypeSlaveServerPlugin,
             final IDataSetTypeSlaveServerPlugin dataSetTypeSlaveServerPlugin)
@@ -758,22 +758,25 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp
         try
         {
             final Session session = getSession(sessionToken);
-            PersonPE person = session.tryGetPerson();
-            if (person != null)
+            synchronized (session) // synchronized with OpenBisSessionManager.updateAllSessions()
             {
-                synchronized (displaySettingsProvider)
+                PersonPE person = session.tryGetPerson();
+                if (person != null)
                 {
-                    if (maxEntityVisits >= 0)
+                    synchronized (displaySettingsProvider)
                     {
-                        List<EntityVisit> visits = displaySettings.getVisits();
-                        sortAndRemoveMultipleVisits(visits);
-                        for (int i = visits.size() - 1; i >= maxEntityVisits; i--)
+                        if (maxEntityVisits >= 0)
                         {
-                            visits.remove(i);
+                            List<EntityVisit> visits = displaySettings.getVisits();
+                            sortAndRemoveMultipleVisits(visits);
+                            for (int i = visits.size() - 1; i >= maxEntityVisits; i--)
+                            {
+                                visits.remove(i);
+                            }
                         }
+                        displaySettingsProvider.replaceRegularDisplaySettings(person, displaySettings);
+                        getDAOFactory().getPersonDAO().updatePerson(person);
                     }
-                    displaySettingsProvider.replaceRegularDisplaySettings(person, displaySettings);
-                    getDAOFactory().getPersonDAO().updatePerson(person);
                 }
             }
         } catch (InvalidSessionException e)
@@ -794,18 +797,21 @@ public abstract class AbstractServer<T> extends AbstractServiceWithLogger<T> imp
         try
         {
             final Session session = getSession(sessionToken);
-            PersonPE person = session.tryGetPerson();
-            if (person != null)
+            synchronized (session) // synchronized with OpenBisSessionManager.updateAllSessions()
             {
-                synchronized (displaySettingsProvider)
+                PersonPE person = session.tryGetPerson();
+                if (person != null)
                 {
-                    DisplaySettings currentDisplaySettings =
-                            displaySettingsProvider.getCurrentDisplaySettings(person);
-                    DisplaySettings newDisplaySettings =
-                            displaySettingsUpdate.update(currentDisplaySettings);
-                    displaySettingsProvider.replaceCurrentDisplaySettings(person,
-                            newDisplaySettings);
-                    getDAOFactory().getPersonDAO().updatePerson(person);
+                    synchronized (displaySettingsProvider)
+                    {
+                        DisplaySettings currentDisplaySettings =
+                                displaySettingsProvider.getCurrentDisplaySettings(person);
+                        DisplaySettings newDisplaySettings =
+                                displaySettingsUpdate.update(currentDisplaySettings);
+                        displaySettingsProvider.replaceCurrentDisplaySettings(person,
+                                newDisplaySettings);
+                        getDAOFactory().getPersonDAO().updatePerson(person);
+                    }
                 }
             }
         } catch (InvalidSessionException e)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
index 433990ee560..d51c6aeecdb 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
@@ -39,7 +39,6 @@ import org.springframework.dao.DataAccessException;
 import org.springframework.dao.DataIntegrityViolationException;
 
 import ch.systemsx.cisd.authentication.IAuthenticationService;
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.mail.IMailClient;
@@ -359,7 +358,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     private String defaultPutDataStoreServerCodeOrNull;
 
     public CommonServer(final IAuthenticationService authenticationService,
-            final ISessionManager<Session> sessionManager, final IDAOFactory daoFactory,
+            final IOpenBisSessionManager sessionManager, final IDAOFactory daoFactory,
             final ICommonBusinessObjectFactory businessObjectFactory,
             IDataStoreServiceRegistrator dataStoreServiceRegistrator,
             final LastModificationState lastModificationState,
@@ -373,7 +372,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     CommonServer(final IAuthenticationService authenticationService,
-            final ISessionManager<Session> sessionManager, final IDAOFactory daoFactory,
+            final IOpenBisSessionManager sessionManager, final IDAOFactory daoFactory,
             IPropertiesBatchManager propertiesBatchManager,
             final ICommonBusinessObjectFactory businessObjectFactory,
             IDataStoreServiceRegistrator dataStoreServiceRegistrator,
@@ -471,7 +470,6 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         {
             registerSpaceRole(sessionToken, RoleCode.ADMIN, new SpaceIdentifier(spaceCode),
                     Grantee.createPerson(session.getUserName()));
-            session.setPerson(getDAOFactory().getPersonDAO().getPerson(person.getId()));
         }
     }
 
@@ -532,13 +530,10 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         final Session session = getSession(sessionToken);
 
         final NewRoleAssignment newRoleAssignment = new NewRoleAssignment();
-        newRoleAssignment.setGrantee(grantee);
         newRoleAssignment.setSpaceIdentifier(spaceIdentifier);
-        newRoleAssignment.setRole(roleCode);
 
-        final IRoleAssignmentTable table = businessObjectFactory.createRoleAssignmentTable(session);
-        table.add(newRoleAssignment);
-        table.save();
+        registerRole(roleCode, grantee, session, newRoleAssignment);
+
     }
 
     @Override
@@ -548,15 +543,22 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         final Session session = getSession(sessionToken);
 
         final NewRoleAssignment newRoleAssignment = new NewRoleAssignment();
-        newRoleAssignment.setGrantee(grantee);
         newRoleAssignment.setDatabaseInstanceIdentifier(new DatabaseInstanceIdentifier(
                 DatabaseInstanceIdentifier.HOME));
+
+        registerRole(roleCode, grantee, session, newRoleAssignment);
+    }
+
+    protected void registerRole(RoleCode roleCode, Grantee grantee, final Session session, final NewRoleAssignment newRoleAssignment)
+    {
+        newRoleAssignment.setGrantee(grantee);
         newRoleAssignment.setRole(roleCode);
 
         final IRoleAssignmentTable table = businessObjectFactory.createRoleAssignmentTable(session);
         table.add(newRoleAssignment);
         table.save();
 
+        sessionManager.updateAllSessions(getDAOFactory());
     }
 
     @Override
@@ -595,6 +597,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             }
         }
         getDAOFactory().getRoleAssignmentDAO().deleteRoleAssignment(roleAssignment);
+        sessionManager.updateAllSessions(getDAOFactory());
     }
 
     @Override
@@ -619,6 +622,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
                             + "Ask another instance admin to do that for you.");
         }
         roleAssignmentDAO.deleteRoleAssignment(roleAssignment);
+        sessionManager.updateAllSessions(getDAOFactory());
     }
 
     @Override
@@ -2311,6 +2315,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         {
             spaceBO.deleteByTechId(id, reason);
         }
+        sessionManager.updateAllSessions(getDAOFactory());
     }
 
     @Override
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/IOpenBisSessionManager.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/IOpenBisSessionManager.java
new file mode 100644
index 00000000000..246819165e9
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/IOpenBisSessionManager.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2013 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server;
+
+import ch.systemsx.cisd.authentication.ISessionManager;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+
+/**
+ * @author Jakub Straszewski
+ */
+public interface IOpenBisSessionManager extends ISessionManager<Session>
+{
+    public void updateAllSessions(IDAOFactory daoFactory);
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/OpenBisSessionManager.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/OpenBisSessionManager.java
new file mode 100644
index 00000000000..a404e7c904f
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/OpenBisSessionManager.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server;
+
+import ch.systemsx.cisd.authentication.DefaultSessionManager;
+import ch.systemsx.cisd.authentication.IAuthenticationService;
+import ch.systemsx.cisd.authentication.ILogMessagePrefixGenerator;
+import ch.systemsx.cisd.authentication.ISessionFactory;
+import ch.systemsx.cisd.common.server.IRemoteHostProvider;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
+
+/**
+ * @author Jakub Straszewski
+ */
+public class OpenBisSessionManager extends DefaultSessionManager<Session> implements IOpenBisSessionManager
+{
+
+    public OpenBisSessionManager(ISessionFactory<Session> sessionFactory, ILogMessagePrefixGenerator<Session> prefixGenerator,
+            IAuthenticationService authenticationService, IRemoteHostProvider remoteHostProvider, int sessionExpirationPeriodMinutes,
+            boolean tryEmailAsUserName)
+    {
+        super(sessionFactory, prefixGenerator, authenticationService, remoteHostProvider, sessionExpirationPeriodMinutes, tryEmailAsUserName);
+    }
+
+    public OpenBisSessionManager(ISessionFactory<Session> sessionFactory, ILogMessagePrefixGenerator<Session> prefixGenerator,
+            IAuthenticationService authenticationService, IRemoteHostProvider remoteHostProvider, int sessionExpirationPeriodMinutes)
+    {
+        super(sessionFactory, prefixGenerator, authenticationService, remoteHostProvider, sessionExpirationPeriodMinutes);
+    }
+
+    @Override
+    public void updateAllSessions(IDAOFactory daoFactory)
+    {
+        synchronized (sessions)
+        {
+            for (FullSession<Session> fullSession : sessions.values())
+            {
+                Session session = fullSession.getSession();
+                synchronized (session) // synchronized with updateDisplaySettings() and saveDisplaySettings() in AbstractServer
+                {
+                    PersonPE oldPerson = session.tryGetPerson();
+                    if (oldPerson != null
+                            && oldPerson.isSystemUser() == false)
+                    {
+                        PersonPE person = daoFactory.getPersonDAO().getPerson(oldPerson.getId());
+                        HibernateUtils.initialize(person.getAllPersonRoles());
+                        session.setPerson(person);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServer.java
index 9b5645b0e1b..b86ba07b22f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServer.java
@@ -286,7 +286,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
     private IManagedPropertyEvaluatorFactory managedPropertyEvaluatorFactory;
 
     public ServiceForDataStoreServer(IAuthenticationService authenticationService,
-            ISessionManager<Session> sessionManager, IDAOFactory daoFactory,
+            IOpenBisSessionManager sessionManager, IDAOFactory daoFactory,
             ICommonBusinessObjectFactory boFactory, IDataStoreServiceFactory dssFactory,
             TrustedCrossOriginDomainsProvider trustedOriginDomainProvider,
             IETLEntityOperationChecker entityOperationChecker,
@@ -309,7 +309,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
     }
 
     ServiceForDataStoreServer(IAuthenticationService authenticationService,
-            ISessionManager<Session> sessionManager, IDAOFactory daoFactory,
+            IOpenBisSessionManager sessionManager, IDAOFactory daoFactory,
             IPropertiesBatchManager propertiesBatchManager, ICommonBusinessObjectFactory boFactory,
             IDataStoreServiceFactory dssFactory,
             TrustedCrossOriginDomainsProvider trustedOriginDomainProvider,
@@ -2030,15 +2030,16 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
         // create space
         ISpaceBO groupBO = businessObjectFactory.createSpaceBO(session);
         groupBO.define(newSpace.getCode(), newSpace.getDescription());
+        SpacePE space = groupBO.getSpace();
+
         if (registratorUserIdOrNull != null)
         {
-            groupBO.getSpace().setRegistrator(
+            space.setRegistrator(
                     getOrCreatePerson(session.getSessionToken(), registratorUserIdOrNull));
         }
         groupBO.save();
 
         // create ADMIN role assignemnt
-        SpacePE space = groupBO.getSpace();
         if (newSpace.getSpaceAdminUserId() != null)
         {
             IRoleAssignmentTable roleTable =
@@ -2051,6 +2052,8 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
             assignment.setGrantee(grantee);
             roleTable.add(assignment);
             roleTable.save();
+
+            sessionManager.updateAllSessions(getDAOFactory());
         }
         return space;
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/TrackingServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/TrackingServer.java
index af92a983170..3eaffc9813e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/TrackingServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/TrackingServer.java
@@ -21,7 +21,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
 import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager;
@@ -45,13 +44,13 @@ public final class TrackingServer extends AbstractServer<ITrackingServer> implem
 {
     private final ICommonBusinessObjectFactory businessObjectFactory;
 
-    public TrackingServer(final ISessionManager<Session> sessionManager,
+    public TrackingServer(final IOpenBisSessionManager sessionManager,
             final IDAOFactory daoFactory, final ICommonBusinessObjectFactory businessObjectFactory)
     {
         this(sessionManager, daoFactory, null, businessObjectFactory);
     }
 
-    TrackingServer(final ISessionManager<Session> sessionManager, final IDAOFactory daoFactory,
+    TrackingServer(final IOpenBisSessionManager sessionManager, final IDAOFactory daoFactory,
             IPropertiesBatchManager propertiesBatchManager,
             final ICommonBusinessObjectFactory businessObjectFactory)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
index a524cc9355b..eacc31e7b51 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
@@ -23,10 +23,10 @@ import javax.annotation.Resource;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.common.exceptions.InvalidSessionException;
 import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.openbis.generic.server.AbstractServer;
+import ch.systemsx.cisd.openbis.generic.server.IOpenBisSessionManager;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
 import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
@@ -63,7 +63,7 @@ public class GeneralInformationChangingService extends
     {
     }
 
-    GeneralInformationChangingService(ISessionManager<Session> sessionManager,
+    GeneralInformationChangingService(IOpenBisSessionManager sessionManager,
             IDAOFactory daoFactory, IPropertiesBatchManager propertiesBatchManager,
             ICommonServer server)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java
index 8192c511841..b795fe67718 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java
@@ -34,11 +34,11 @@ import org.apache.commons.collections.Transformer;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.openbis.generic.server.AbstractServer;
 import ch.systemsx.cisd.openbis.generic.server.ComponentNames;
+import ch.systemsx.cisd.openbis.generic.server.IOpenBisSessionManager;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.AuthorizationGuard;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Capability;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.ReturnValueFilter;
@@ -154,7 +154,7 @@ public class GeneralInformationService extends AbstractServer<IGeneralInformatio
     {
     }
 
-    GeneralInformationService(ISessionManager<Session> sessionManager, IDAOFactory daoFactory,
+    GeneralInformationService(IOpenBisSessionManager sessionManager, IDAOFactory daoFactory,
             ICommonBusinessObjectFactory boFactory, IPropertiesBatchManager propertiesBatchManager,
             ICommonServer commonServer)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/server/DemoServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/server/DemoServer.java
index 4c50c32cd93..0bcfa35c5a1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/server/DemoServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/server/DemoServer.java
@@ -23,12 +23,12 @@ import javax.annotation.Resource;
 import org.springframework.stereotype.Component;
 
 import ch.rinn.restrictions.Private;
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.common.exceptions.NotImplementedException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.openbis.generic.server.AbstractServer;
 import ch.systemsx.cisd.openbis.generic.server.ComponentNames;
+import ch.systemsx.cisd.openbis.generic.server.IOpenBisSessionManager;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.AuthorizationGuard;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.NewSamplePredicate;
@@ -73,7 +73,7 @@ public final class DemoServer extends AbstractServer<IDemoServer> implements IDe
     }
 
     @Private
-    DemoServer(final ISessionManager<Session> sessionManager, final IDAOFactory daoFactory,
+    DemoServer(final IOpenBisSessionManager sessionManager, final IDAOFactory daoFactory,
             IPropertiesBatchManager propertiesBatchManager,
             final IDemoBusinessObjectFactory businessObjectFactory,
             final ISampleTypeSlaveServerPlugin sampleTypeSlaveServerPlugin,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
index 0c552a34e4c..acf8b1b1a29 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
@@ -32,13 +32,13 @@ import javax.annotation.Resource;
 import org.springframework.stereotype.Component;
 
 import ch.rinn.restrictions.Private;
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.openbis.generic.server.AbstractASyncAction;
 import ch.systemsx.cisd.openbis.generic.server.AbstractServer;
 import ch.systemsx.cisd.openbis.generic.server.ComponentNames;
+import ch.systemsx.cisd.openbis.generic.server.IOpenBisSessionManager;
 import ch.systemsx.cisd.openbis.generic.server.MaterialHelper;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.AuthorizationGuard;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Capability;
@@ -153,7 +153,7 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
     }
 
     @Private
-    GenericServer(final ISessionManager<Session> sessionManager, final IDAOFactory daoFactory,
+    GenericServer(final IOpenBisSessionManager sessionManager, final IDAOFactory daoFactory,
             IPropertiesBatchManager propertiesBatchManager,
             final IGenericBusinessObjectFactory businessObjectFactory,
             final ISampleTypeSlaveServerPlugin sampleTypeSlaveServerPlugin,
@@ -899,8 +899,7 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
 
     /**
      * @param sessionToken The session token for the request
-     * @param experiments Should be a NewExperimentsWithType where the newExperiments contains a
-     *            collection of {@link UpdatedBasicExperiment} objects.
+     * @param experiments Should be a NewExperimentsWithType where the newExperiments contains a collection of {@link UpdatedBasicExperiment} objects.
      */
     @Override
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
@@ -937,8 +936,7 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
     }
 
     /**
-     * @param updatedExperiments The experiments should actually be instances of
-     *            UpdatedBasicExperiment.
+     * @param updatedExperiments The experiments should actually be instances of UpdatedBasicExperiment.
      */
     private List<ExperimentBatchUpdatesDTO> convertExperiments(
             final List<UpdatedBasicExperiment> updatedExperiments)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/QueryServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/QueryServer.java
index 2392d868c36..07a2714ce05 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/QueryServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/QueryServer.java
@@ -30,10 +30,10 @@ import org.springframework.dao.DataAccessException;
 import org.springframework.stereotype.Component;
 
 import ch.rinn.restrictions.Private;
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.openbis.generic.server.AbstractServer;
+import ch.systemsx.cisd.openbis.generic.server.IOpenBisSessionManager;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.ReturnValueFilter;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
 import ch.systemsx.cisd.openbis.generic.server.authorization.validator.ExpressionValidator;
@@ -84,7 +84,7 @@ public class QueryServer extends AbstractServer<IQueryServer> implements IQueryS
     }
 
     @Private
-    QueryServer(final ISessionManager<Session> sessionManager, final IDAOFactory daoFactory,
+    QueryServer(final IOpenBisSessionManager sessionManager, final IDAOFactory daoFactory,
             IPropertiesBatchManager propertiesBatchManager,
             final ISampleTypeSlaveServerPlugin sampleTypeSlaveServerPlugin,
             final IDataSetTypeSlaveServerPlugin dataSetTypeSlaveServerPlugin,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/api/v1/QueryApiServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/api/v1/QueryApiServer.java
index 18e608c19d7..3b2796d18b4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/api/v1/QueryApiServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/api/v1/QueryApiServer.java
@@ -26,9 +26,9 @@ import javax.annotation.Resource;
 
 import org.springframework.stereotype.Component;
 
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.openbis.generic.server.AbstractServer;
+import ch.systemsx.cisd.openbis.generic.server.IOpenBisSessionManager;
 import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
 import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
@@ -42,7 +42,6 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataStoreServicePE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
 import ch.systemsx.cisd.openbis.plugin.query.shared.IQueryServer;
 import ch.systemsx.cisd.openbis.plugin.query.shared.api.v1.IQueryApiServer;
@@ -71,7 +70,7 @@ public class QueryApiServer extends AbstractServer<IQueryApiServer> implements I
     }
 
     public QueryApiServer(IQueryServer queryServer, ICommonServer commonServer,
-            ISessionManager<Session> sessionManager, IDAOFactory daoFactory,
+            IOpenBisSessionManager sessionManager, IDAOFactory daoFactory,
             IPropertiesBatchManager propertiesBatchManager)
     {
         super(sessionManager, daoFactory, propertiesBatchManager);
diff --git a/openbis/source/java/genericApplicationContext.xml b/openbis/source/java/genericApplicationContext.xml
index 061fb80926a..56d52123239 100644
--- a/openbis/source/java/genericApplicationContext.xml
+++ b/openbis/source/java/genericApplicationContext.xml
@@ -103,7 +103,7 @@
         <constructor-arg ref="${authentication-service}" />
     </bean>
 
-    <bean id="session-manager" class="ch.systemsx.cisd.authentication.DefaultSessionManager">
+    <bean id="session-manager" class="ch.systemsx.cisd.openbis.generic.server.OpenBisSessionManager">
         <constructor-arg>
             <bean class="ch.systemsx.cisd.openbis.generic.server.SessionFactory">
                 <constructor-arg ref="dao-factory" />
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/AbstractServerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/AbstractServerTest.java
index 0636c340115..5ed6d5af4f0 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/AbstractServerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/AbstractServerTest.java
@@ -27,10 +27,9 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.authentication.Principal;
-import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.common.test.RecordingMatcher;
+import ch.systemsx.cisd.openbis.common.spring.IInvocationLoggerContext;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IPersonDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IRoleAssignmentDAO;
@@ -58,7 +57,7 @@ public class AbstractServerTest extends AssertJUnit
 
     private AbstractServer<Object> server;
 
-    private ISessionManager<Session> sessionManager;
+    private IOpenBisSessionManager sessionManager;
 
     private IDAOFactory daoFactory;
 
@@ -67,12 +66,12 @@ public class AbstractServerTest extends AssertJUnit
     private IRoleAssignmentDAO roleAssigmentDAO;
 
     @SuppressWarnings(
-        { "cast", "unchecked" })
+    { "cast", "unchecked" })
     @BeforeMethod
     public void beforeMethod()
     {
         context = new Mockery();
-        sessionManager = (ISessionManager<Session>) context.mock(ISessionManager.class);
+        sessionManager = (IOpenBisSessionManager) context.mock(IOpenBisSessionManager.class);
         daoFactory = context.mock(IDAOFactory.class);
         personDAO = context.mock(IPersonDAO.class);
         roleAssigmentDAO = context.mock(IRoleAssignmentDAO.class);
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java
index e9d798eb42e..4ba8784260d 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java
@@ -40,7 +40,6 @@ import ch.systemsx.cisd.common.logging.LogLevel;
 import ch.systemsx.cisd.common.test.RecordingMatcher;
 import ch.systemsx.cisd.openbis.generic.server.business.IDataStoreServiceFactory;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
-import ch.systemsx.cisd.openbis.generic.server.business.bo.IRoleAssignmentTable;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.IDynamicPropertyCalculatorFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.DynamicPropertyCalculatorFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.entity_validation.EntityValidatorFactory;
@@ -65,6 +64,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityVisit;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Grantee;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LastModificationState;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListMaterialCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialType;
@@ -113,6 +113,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.builders.ScriptPEBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.hotdeploy_plugins.api.ICommonPropertyBasedHotDeployPlugin;
 import ch.systemsx.cisd.openbis.generic.shared.managed_property.IManagedPropertyEvaluatorFactory;
 import ch.systemsx.cisd.openbis.generic.shared.managed_property.ManagedPropertyEvaluatorFactory;
@@ -160,8 +161,6 @@ public final class CommonServerTest extends AbstractServerTestCase
 
     private IDataStoreService dataStoreService;
 
-    private IRoleAssignmentTable roleAssignmentTable;
-
     private final CommonServer createServer()
     {
         CommonServer server =
@@ -210,7 +209,6 @@ public final class CommonServerTest extends AbstractServerTestCase
         entityValidatorFactory = context.mock(IEntityValidatorFactory.class);
         entityValidatorHotDeployPlugin = context.mock(IEntityValidatorHotDeployPlugin.class);
         hotDeploymentController = context.mock(IHotDeploymentController.class);
-        roleAssignmentTable = context.mock(IRoleAssignmentTable.class);
     }
 
     @Test
@@ -463,10 +461,10 @@ public final class CommonServerTest extends AbstractServerTestCase
             {
                 {
                     one(commonBusinessObjectFactory).createSpaceBO(session);
-                    will(returnValue(groupBO));
+                    will(returnValue(spaceBO));
 
-                    one(groupBO).define(spaceCode, description);
-                    one(groupBO).save();
+                    one(spaceBO).define(spaceCode, description);
+                    one(spaceBO).save();
 
                     one(personDAO).tryFindPersonByUserId(CommonTestUtils.USER_ID);
                     will(returnValue(person));
@@ -477,18 +475,94 @@ public final class CommonServerTest extends AbstractServerTestCase
                     one(roleAssignmentTable).add(with(assignmentMatcher));
                     one(roleAssignmentTable).save();
 
-                    one(personDAO).getPerson(4);
-                    will(returnValue(person));
+                    one(sessionManager).updateAllSessions(daoFactory);
+
                 }
             });
 
         createServer().registerSpace(SESSION_TOKEN, spaceCode, description);
 
-        assertSame(person, session.tryGetPerson());
         assertEquals("PERSON:test=ADMIN@/group", assignmentMatcher.recordedObject().toString());
         context.assertIsSatisfied();
     }
 
+    @Test
+    public void testRegisterInstanceRoleAssignment()
+    {
+        prepareGetSession();
+        final RecordingMatcher<NewRoleAssignment> assignmentMatcher =
+                new RecordingMatcher<NewRoleAssignment>();
+        context.checking(new Expectations()
+            {
+                {
+                    one(commonBusinessObjectFactory).createRoleAssignmentTable(session);
+                    will(returnValue(roleAssignmentTable));
+
+                    one(roleAssignmentTable).add(with(assignmentMatcher));
+                    one(roleAssignmentTable).save();
+
+                    one(sessionManager).updateAllSessions(daoFactory);
+                }
+            });
+
+        createServer().registerInstanceRole(SESSION_TOKEN, RoleCode.ADMIN, Grantee.createPerson(CommonTestUtils.USER_ID));
+
+        assertEquals("PERSON:test=ADMIN@", assignmentMatcher.recordedObject().toString());
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testDeleteSpaceRole()
+    {
+        prepareGetSession();
+        final Grantee person = Grantee.createPerson(CommonTestUtils.USER_ID);
+        context.checking(new Expectations()
+            {
+                {
+                    one(roleAssignmentDAO).tryFindSpaceRoleAssignment(RoleCode.USER, "S42", person);
+                    RoleAssignmentPE assignment = new RoleAssignmentPE();
+                    assignment.setDatabaseInstance(new DatabaseInstancePE());
+                    assignment.setRole(RoleCode.USER);
+                    assignment.setPersonInternal(new PersonPE());
+                    will(returnValue(assignment));
+
+                    one(roleAssignmentDAO).deleteRoleAssignment(assignment);
+
+                    one(sessionManager).updateAllSessions(daoFactory);
+                }
+            });
+
+        createServer().deleteSpaceRole(SESSION_TOKEN, RoleCode.USER, new SpaceIdentifier("S42"), person);
+
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testDeleteInstanceRole()
+    {
+        prepareGetSession();
+        final Grantee person = Grantee.createPerson(CommonTestUtils.USER_ID);
+        context.checking(new Expectations()
+            {
+                {
+                    one(roleAssignmentDAO).tryFindInstanceRoleAssignment(RoleCode.USER, person);
+                    RoleAssignmentPE assignment = new RoleAssignmentPE();
+                    assignment.setDatabaseInstance(new DatabaseInstancePE());
+                    assignment.setRole(RoleCode.USER);
+                    assignment.setPersonInternal(new PersonPE());
+                    will(returnValue(assignment));
+
+                    one(roleAssignmentDAO).deleteRoleAssignment(assignment);
+
+                    one(sessionManager).updateAllSessions(daoFactory);
+                }
+            });
+
+        createServer().deleteInstanceRole(SESSION_TOKEN, RoleCode.USER, person);
+
+        context.assertIsSatisfied();
+    }
+
     @Test
     public void testListPersons()
     {
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java
index baf0ad10f4c..4edcad6437b 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java
@@ -106,6 +106,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.MaterialUpdateDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.dto.NewRoleAssignment;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PropertyTypePE;
@@ -119,6 +120,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SampleTypePropertyTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SimpleDataSetInformationDTO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.builders.DatabaseInstancePEBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier;
@@ -153,6 +155,12 @@ public class ETLServiceTest extends AbstractServerTestCase
 
     private static final String USER_FOR_ENTITY_OPERATIONS = "eo-user";
 
+    private static final String TEST_SPACE = "TEST-SPACE-CREATED-WITH-DSS";
+
+    private static final String TEST_SPACE_DESCRIPTION = "some description";
+
+    private static final String TEST_SPACE_USER = "test_space";
+
     private ICommonBusinessObjectFactory boFactory;
 
     private IDataStoreServiceFactory dssfactory;
@@ -1077,7 +1085,7 @@ public class ETLServiceTest extends AbstractServerTestCase
         dataSetUpdate.setDatasetId(CommonTestUtils.TECH_ID);
         dataSetUpdate.setFileFormatTypeCode("new-file-format");
         dataSetUpdate.setModifiedContainedDatasetCodesOrNull(new String[]
-            { "c1", "c2" });
+        { "c1", "c2" });
 
         final MetaprojectPE metaprojectPE = new MetaprojectPE();
 
@@ -1099,13 +1107,15 @@ public class ETLServiceTest extends AbstractServerTestCase
 
         List<VocabularyUpdatesDTO> vocabularyUpdates = Collections.emptyList();
 
-        prepareEntityOperationsExpectations(samplePE, sampleUpdate, material, materialType,
+        NewSpace space = new NewSpace(TEST_SPACE, TEST_SPACE_DESCRIPTION, TEST_SPACE_USER);
+
+        RecordingMatcher<NewRoleAssignment> roleMatcher = prepareEntityOperationsExpectations(samplePE, sampleUpdate, material, materialType,
                 materialRegistrations, newSamplePE, newSampleIdentifier, newSample, externalData,
-                updatedDataSetCode, dataSetUpdate, newMetaproject, metaprojectPE, mtu);
+                updatedDataSetCode, dataSetUpdate, newMetaproject, metaprojectPE, mtu, space);
 
         AtomicEntityOperationDetails details =
                 new AtomicEntityOperationDetails(null, USER_FOR_ENTITY_OPERATIONS,
-                        new ArrayList<NewSpace>(), new ArrayList<NewProject>(),
+                        Arrays.asList(space), new ArrayList<NewProject>(),
                         new ArrayList<ProjectUpdatesDTO>(), new ArrayList<NewExperiment>(),
                         experimentUpdates, Collections.singletonList(sampleUpdate),
                         Collections.singletonList(newSample), materialRegistrations,
@@ -1120,20 +1130,23 @@ public class ETLServiceTest extends AbstractServerTestCase
         assertEquals(1, result.getSamplesUpdatedCount());
         assertEquals(1, result.getSamplesCreatedCount());
         assertEquals(1, result.getDataSetsUpdatedCount());
+        assertEquals(TEST_SPACE, roleMatcher.recordedObject().getSpaceIdentifier().getSpaceCode());
+        assertEquals(TEST_SPACE_USER, roleMatcher.recordedObject().getGrantee().getCode());
 
         context.assertIsSatisfied();
     }
 
-    private void prepareEntityOperationsExpectations(final SamplePE samplePE,
+    private RecordingMatcher<NewRoleAssignment> prepareEntityOperationsExpectations(final SamplePE samplePE,
             final SampleUpdatesDTO sampleUpdate, final MaterialPE material,
             final MaterialTypePE materialType, final Map<String, List<NewMaterial>> newMaterials,
             final SamplePE newSamplePE, final SampleIdentifier newSampleIdentifier,
             final NewSample newSample, final NewExternalData externalData,
             final String updatedDataSetCode, final DataSetBatchUpdatesDTO dataSetUpdate,
             final NewMetaproject newMetaproject, final MetaprojectPE metaprojectPE,
-            final MetaprojectUpdatesDTO metaprojectUpdates)
+            final MetaprojectUpdatesDTO metaprojectUpdates, final NewSpace newSpace)
     {
         final Session userSession = createSession(USER_FOR_ENTITY_OPERATIONS);
+        final RecordingMatcher<NewRoleAssignment> roleMatcher = new RecordingMatcher<NewRoleAssignment>();
         context.checking(new Expectations()
             {
                 {
@@ -1147,6 +1160,27 @@ public class ETLServiceTest extends AbstractServerTestCase
 
                     one(sessionManagerForEntityOperations).closeSession(sessionToken);
 
+                    one(entityOperationChecker).assertSpaceCreationAllowed(userSession, Arrays.asList(newSpace));
+                    one(boFactory).createSpaceBO(userSession);
+                    will(returnValue(spaceBO));
+
+                    one(spaceBO).define(TEST_SPACE, TEST_SPACE_DESCRIPTION);
+                    one(spaceBO).save();
+
+                    one(spaceBO).getSpace();
+                    SpacePE space = new SpacePE();
+                    space.setCode(TEST_SPACE);
+                    space.setDescription(TEST_SPACE_DESCRIPTION);
+                    will(returnValue(space));
+
+                    one(boFactory).createRoleAssignmentTable(userSession);
+                    will(returnValue(roleAssignmentTable));
+
+                    one(roleAssignmentTable).add(with(roleMatcher));
+                    one(roleAssignmentTable).save();
+
+                    one(sessionManager).updateAllSessions(daoFactory);
+
                     allowing(personDAO).tryFindPersonByUserId(USER_FOR_ENTITY_OPERATIONS);
                     PersonPE user = createSystemUser();
                     will(returnValue(user));
@@ -1269,6 +1303,7 @@ public class ETLServiceTest extends AbstractServerTestCase
                     // will(returnValue(externalDataPE));
                 }
             });
+        return roleMatcher;
     }
 
     @Test
@@ -1315,7 +1350,7 @@ public class ETLServiceTest extends AbstractServerTestCase
         dataSetUpdate.setDatasetId(CommonTestUtils.TECH_ID);
         dataSetUpdate.setFileFormatTypeCode("new-file-format");
         dataSetUpdate.setModifiedContainedDatasetCodesOrNull(new String[]
-            { "c1", "c2" });
+        { "c1", "c2" });
 
         final MetaprojectPE metaprojectPE = new MetaprojectPE();
         metaprojectPE.setOwner(CommonTestUtils.createPersonFromPrincipal(PRINCIPAL));
@@ -1338,9 +1373,11 @@ public class ETLServiceTest extends AbstractServerTestCase
 
         List<VocabularyUpdatesDTO> vocabularyUpdates = Collections.emptyList();
 
-        prepareEntityOperationsExpectations(samplePE, sampleUpdate, material, materialType,
+        NewSpace space = new NewSpace(TEST_SPACE, TEST_SPACE_DESCRIPTION, TEST_SPACE_USER);
+
+        RecordingMatcher<NewRoleAssignment> roleMatcher = prepareEntityOperationsExpectations(samplePE, sampleUpdate, material, materialType,
                 materialRegistrations, newSamplePE, newSampleIdentifier, newSample, externalData,
-                updatedDataSetCode, dataSetUpdate, newMetaproject, metaprojectPE, mtu);
+                updatedDataSetCode, dataSetUpdate, newMetaproject, metaprojectPE, mtu, space);
         context.checking(new Expectations()
             {
                 {
@@ -1351,7 +1388,7 @@ public class ETLServiceTest extends AbstractServerTestCase
 
         AtomicEntityOperationDetails details =
                 new AtomicEntityOperationDetails(new TechId(1), USER_FOR_ENTITY_OPERATIONS,
-                        new ArrayList<NewSpace>(), new ArrayList<NewProject>(),
+                        Arrays.asList(space), new ArrayList<NewProject>(),
                         new ArrayList<ProjectUpdatesDTO>(), new ArrayList<NewExperiment>(),
                         new ArrayList<ExperimentUpdatesDTO>(),
                         Collections.singletonList(sampleUpdate),
@@ -1368,6 +1405,9 @@ public class ETLServiceTest extends AbstractServerTestCase
         assertEquals(1, result.getSamplesCreatedCount());
         assertEquals(1, result.getDataSetsUpdatedCount());
 
+        assertEquals(TEST_SPACE, roleMatcher.recordedObject().getSpaceIdentifier().getSpaceCode());
+        assertEquals(TEST_SPACE_USER, roleMatcher.recordedObject().getGrantee().getCode());
+
         context.assertIsSatisfied();
     }
 
@@ -1583,7 +1623,7 @@ public class ETLServiceTest extends AbstractServerTestCase
     {
         // unknown data set type codes should be silently discarded
         return new DatastoreServiceDescription(key, key, new String[]
-            { DATA_SET_TYPE_CODE, UNKNOWN_DATA_SET_TYPE_CODE }, key, serviceKind);
+        { DATA_SET_TYPE_CODE, UNKNOWN_DATA_SET_TYPE_CODE }, key, serviceKind);
     }
 
     @SuppressWarnings("deprecation")
@@ -1592,7 +1632,7 @@ public class ETLServiceTest extends AbstractServerTestCase
     {
         // wildcards should be handled correctly
         return new DatastoreServiceDescription(key, key, new String[]
-            { regex }, key, serviceKind);
+        { regex }, key, serviceKind);
     }
 
     private void assignRoles(PersonPE person)
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/AbstractServerTestCase.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/AbstractServerTestCase.java
index bbbcd0fe516..02ff8483609 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/AbstractServerTestCase.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/AbstractServerTestCase.java
@@ -27,11 +27,11 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 
 import ch.systemsx.cisd.authentication.IAuthenticationService;
-import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.authentication.Principal;
 import ch.systemsx.cisd.common.logging.BufferedAppender;
 import ch.systemsx.cisd.common.logging.LogInitializer;
 import ch.systemsx.cisd.openbis.generic.server.CommonServerTest.PersonWithDisplaySettingsMatcher;
+import ch.systemsx.cisd.openbis.generic.server.IOpenBisSessionManager;
 import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDataBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IDataSetTable;
@@ -46,6 +46,7 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.IMaterialTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IMetaprojectBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IPropertyTypeBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IPropertyTypeTable;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IRoleAssignmentTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ISampleBO;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ISampleTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.IScriptBO;
@@ -116,7 +117,7 @@ public abstract class AbstractServerTestCase extends AssertJUnit
 
     protected IAuthenticationService authenticationService;
 
-    protected ISessionManager<Session> sessionManager;
+    protected IOpenBisSessionManager sessionManager;
 
     protected IDatabaseInstanceDAO databaseInstanceDAO;
 
@@ -134,7 +135,7 @@ public abstract class AbstractServerTestCase extends AssertJUnit
 
     protected ISampleDAO sampleDAO;
 
-    protected ISpaceBO groupBO;
+    protected ISpaceBO spaceBO;
 
     protected ISampleBO sampleBO;
 
@@ -212,6 +213,8 @@ public abstract class AbstractServerTestCase extends AssertJUnit
 
     protected IScriptBO scriptBO;
 
+    protected IRoleAssignmentTable roleAssignmentTable;
+
     private MaterialConfigurationProvider oldProvider;
 
     @BeforeMethod
@@ -223,7 +226,7 @@ public abstract class AbstractServerTestCase extends AssertJUnit
         logRecorder = new BufferedAppender("%m%n", Level.DEBUG);
         context = new Mockery();
         authenticationService = context.mock(IAuthenticationService.class);
-        sessionManager = context.mock(ISessionManager.class);
+        sessionManager = context.mock(IOpenBisSessionManager.class);
         propertiesBatchManager = context.mock(IPropertiesBatchManager.class);
         // DAO
         daoFactory = context.mock(IDAOFactory.class);
@@ -251,7 +254,7 @@ public abstract class AbstractServerTestCase extends AssertJUnit
         metaprojectDAO = context.mock(IMetaprojectDAO.class);
         scriptDAO = context.mock(IScriptDAO.class);
         // BO
-        groupBO = context.mock(ISpaceBO.class);
+        spaceBO = context.mock(ISpaceBO.class);
         entityTypeBO = context.mock(IEntityTypeBO.class);
         sampleBO = context.mock(ISampleBO.class);
         materialBO = context.mock(IMaterialBO.class);
@@ -274,6 +277,7 @@ public abstract class AbstractServerTestCase extends AssertJUnit
         propertyTypeTable = context.mock(IPropertyTypeTable.class);
         materialTable = context.mock(IMaterialTable.class);
         materialLister = context.mock(IMaterialLister.class);
+        roleAssignmentTable = context.mock(IRoleAssignmentTable.class);
 
         homeDatabaseInstance = CommonTestUtils.createHomeDatabaseInstance();
         context.checking(new Expectations()
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/CommonServerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/CommonServerTest.java
index db4ab76329c..f69f8fbca47 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/CommonServerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/CommonServerTest.java
@@ -22,23 +22,99 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.Predicate;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ColumnSetting;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ContainerDataSet;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityTypePropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Grantee;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy.RoleCode;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.displaysettings.ColumnDisplaySettingsUpdate;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 
 /**
  * @author Franz-Josef Elmer
  */
+@Transactional(propagation = Propagation.NOT_SUPPORTED)
 public class CommonServerTest extends SystemTestCase
 {
+    @Test
+    public void testRoleAssingmentDeleted()
+    {
+        String sessionTokenForInstanceAdmin = commonServer.tryAuthenticate("test", "a").getSessionToken();
+        String sessionTokenForSpaceAdmin = commonServer.tryAuthenticate("test_space", "a").getSessionToken();
+
+        // reproduce
+
+        commonServer.deleteSpaceRole(sessionTokenForInstanceAdmin, RoleCode.ADMIN,
+                new SpaceIdentifier("TEST-SPACE"), Grantee.createPerson("test_space"));
+
+        commonServer.updateDisplaySettings(sessionTokenForSpaceAdmin,
+                new ColumnDisplaySettingsUpdate("id_a_b_C", Collections.<ColumnSetting> emptyList()));
+        // clean up
+        commonServer.registerSpaceRole(sessionTokenForInstanceAdmin, RoleCode.ADMIN,
+                new SpaceIdentifier("TEST-SPACE"), Grantee.createPerson("test_space"));
+    }
+
+    @Test
+    public void testRoleAssignmentAdded()
+    {
+        String spaceCode = "TESTGROUP";
+
+        String sessionTokenForInstanceAdmin = commonServer.tryAuthenticate("test", "a").getSessionToken();
+        String sessionTokenForSpaceAdmin = commonServer.tryAuthenticate("test_space", "a").getSessionToken();
+
+        List<Space> spaces = commonServer.listSpaces(sessionTokenForSpaceAdmin, DatabaseInstanceIdentifier.createHome());
+        int matchingSpaces = containstSpace(spaces, spaceCode);
+        assertEquals(spaceCode + " should not be in test_space user groups before the role assignment" + spaces, 0, matchingSpaces);
+
+        commonServer.registerSpaceRole(sessionTokenForInstanceAdmin, RoleCode.ADMIN,
+                new SpaceIdentifier(spaceCode), Grantee.createPerson("test_space"));
+
+        spaces = commonServer.listSpaces(sessionTokenForSpaceAdmin, DatabaseInstanceIdentifier.createHome());
+        matchingSpaces = containstSpace(spaces, spaceCode);
+        assertEquals("Couldn't find " + spaceCode + " space in " + spaces, 1, matchingSpaces);
+
+        // cleanup
+
+        commonServer.deleteSpaceRole(sessionTokenForInstanceAdmin, RoleCode.ADMIN,
+                new SpaceIdentifier(spaceCode), Grantee.createPerson("test_space"));
+
+    }
+
+    private int containstSpace(List<Space> spaces, final String spaceCode)
+    {
+        int matchingSpaces = CollectionUtils.countMatches(spaces, new Predicate<Space>()
+            {
+                @Override
+                public boolean evaluate(Space object)
+                {
+                    return object.getCode().equals(spaceCode);
+                }
+
+            });
+        return matchingSpaces;
+    }
+
+    @AfterClass
+    public void cleanup()
+    {
+    }
+
     @Test
     public void testGetSampleWithAssignedPropertyTypesAndProperties()
     {
-- 
GitLab