From c7c133425462469074a635563d1e9f798d419e81 Mon Sep 17 00:00:00 2001
From: pkupczyk <pkupczyk>
Date: Fri, 22 Dec 2017 15:23:54 +0000
Subject: [PATCH] SSDM-6019 : Project Authorization - modify @RolesAllowed
 annotations at non-entity related methods

SVN: 39070
---
 .../etlserver/api/v1/PutDataSetExecutor.java  |  68 +--------
 .../v1/PutDataSetTopLevelDataSetHandler.java  |  67 +--------
 .../server/DatasetSessionAuthorizer.java      |  53 ++++++-
 .../server/EncapsulatedOpenBISService.java    |  12 ++
 .../shared/IEncapsulatedOpenBISService.java   |   8 ++
 .../DssSessionAuthorizationHolder.java        |  12 ++
 .../authorization/IDssSessionAuthorizer.java  |  14 ++
 .../authorization/NewDataSetPredicate.java    |  23 +--
 .../1/dss/drop-boxes/test/data-set-handler.py |  30 ++--
 .../systemtests/OpenbisServiceFacadeTest.java |  82 ++++++++++-
 .../AtomicOperationsPredicateSystemTest.java  |  60 ++++++++
 ...cateWithDataSetRegistrationSystemTest.java | 100 +++++++++++++
 ...sPredicateWithDataSetUpdateSystemTest.java | 117 +++++++++++++++
 ...eWithExperimentRegistrationSystemTest.java |  53 +++++++
 ...edicateWithExperimentUpdateSystemTest.java |  84 +++++++++++
 ...cateWithProjectRegistrationSystemTest.java |  53 +++++++
 ...sPredicateWithProjectUpdateSystemTest.java |  80 +++++++++++
 ...icateWithSampleRegistrationSystemTest.java |  90 ++++++++++++
 ...nsPredicateWithSampleUpdateSystemTest.java |  88 ++++++++++++
 ...eletionValidatorWithDataSetSystemTest.java |  51 +++++++
 .../server/ServiceForDataStoreServer.java     |  22 ++-
 .../ServiceForDataStoreServerLogger.java      |  20 ++-
 .../predicate/AtomicOperationsPredicate.java  |  18 +--
 ...ampleAugmentedCodeReadWritePredicate.java} |  10 +-
 .../predicate/SampleIdentifierPredicate.java  |   5 +
 .../predicate/SampleListPredicate.java        |  15 +-
 .../SampleOwnerIdentifierPredicate.java       | 104 --------------
 .../business/EntityOperationChecker.java      |   4 +-
 .../business/IEntityOperationChecker.java     |   6 +-
 .../bo/AbstractSampleBusinessObject.java      |  14 +-
 .../shared/IServiceForDataStoreServer.java    |  18 +++
 .../SampleOwnerIdentifierPredicateTest.java   | 136 ------------------
 .../entity/EntityPredicateTestService.java    |   9 ++
 33 files changed, 1074 insertions(+), 452 deletions(-)
 create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateSystemTest.java
 create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithDataSetRegistrationSystemTest.java
 create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithDataSetUpdateSystemTest.java
 create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithExperimentRegistrationSystemTest.java
 create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithExperimentUpdateSystemTest.java
 create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithProjectRegistrationSystemTest.java
 create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithProjectUpdateSystemTest.java
 create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithSampleRegistrationSystemTest.java
 create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithSampleUpdateSystemTest.java
 create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/validator/deletion/DeletionValidatorWithDataSetSystemTest.java
 rename openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/{ExistingSampleOwnerIdentifierPredicate.java => SampleAugmentedCodeReadWritePredicate.java} (68%)
 delete mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleOwnerIdentifierPredicate.java
 delete mode 100644 openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleOwnerIdentifierPredicateTest.java

diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java
index 4fa6464437e..9c49098797c 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetExecutor.java
@@ -75,7 +75,6 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifi
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 
 /**
  * A helper class for carrying out the put command for creating data sets.
@@ -159,6 +158,7 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
         overridingTypeExtractor = new OverridingTypeExtractor();
         handler = plugin.getDataSetHandler(this, service.getOpenBisService());
     }
+
     /**
      * Run the put command; does *not* close the input stream &mdash; clients of the executor are expected to close the input stream when appropriate.
      * 
@@ -166,14 +166,6 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
      */
     public List<DataSetInformation> execute() throws UserFailureException, IOException
     {
-        // Check that the session owner has at least user access to the space the new data
-        // set should belongs to
-        SpaceIdentifier spaceId = getSpaceIdentifierForNewDataSet();
-        if (spaceId != null)
-        {
-            getOpenBisService().checkSpaceAccess(sessionToken, spaceId);
-        }
-
         writeDataSetToTempDirectory();
         overrideOrNull = null;
 
@@ -185,22 +177,13 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
         {
             deleteDataSetDir();
         }
-
     }
+
     /**
      * Run the put command; this method assumes the data set is already in the rpc-icoming folder in the share.
-     * 
      */
     public List<DataSetInformation> executeWithoutWriting() throws UserFailureException
     {
-        // Check that the session owner has at least user access to the space the new data
-        // set should belongs to
-        SpaceIdentifier spaceId = getSpaceIdentifierForNewDataSet();
-        if (spaceId != null)
-        {
-            getOpenBisService().checkSpaceAccess(sessionToken, spaceId);
-        }
-
         overrideOrNull = null;
 
         // Register the data set
@@ -445,53 +428,6 @@ class PutDataSetExecutor implements IDataSetHandlerRpc
         FileUtils.deleteQuietly(fileToDelete);
     }
 
-    private SpaceIdentifier getSpaceIdentifierForNewDataSet()
-    {
-        SpaceIdentifier spaceId = null;
-        DataSetOwner owner = getDataSetOwner();
-        if (owner == null)
-        {
-            return null;
-        }
-
-        switch (owner.getType())
-        {
-            case EXPERIMENT:
-                ExperimentIdentifier experimentId = tryExperimentIdentifier();
-                spaceId =
-                        new SpaceIdentifier(experimentId.getSpaceCode());
-                break;
-            case SAMPLE:
-                SampleIdentifier sampleId = trySampleIdentifier();
-                spaceId = sampleId.getSpaceLevel();
-                break;
-            case DATA_SET:
-                String dataSetCode = tryGetDataSetCode();
-
-                AbstractExternalData parentDataSet = getOpenBisService().tryGetDataSet(dataSetCode);
-                if (parentDataSet != null)
-                {
-                    if (parentDataSet.getExperiment() != null)
-                    {
-                        experimentId =
-                                ExperimentIdentifierFactory.parse(parentDataSet.getExperiment()
-                                        .getIdentifier());
-                        spaceId =
-                                new SpaceIdentifier(experimentId.getSpaceCode());
-                    }
-                    if (parentDataSet.getSample() != null)
-                    {
-                        sampleId =
-                                SampleIdentifierFactory.parse(parentDataSet.getSample()
-                                        .getIdentifier());
-                        spaceId = sampleId.getSpaceLevel();
-                    }
-                }
-                break;
-        }
-        return spaceId;
-    }
-
     private ExperimentIdentifier tryExperimentIdentifier()
     {
         DataSetOwner owner = getDataSetOwner();
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java
index ca5909b5b2e..8c53db59aa7 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetTopLevelDataSetHandler.java
@@ -50,7 +50,6 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifi
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 
 /**
  * A helper class for carrying out the put command for creating data sets.
@@ -132,8 +131,8 @@ class PutDataSetTopLevelDataSetHandler
                     + dataSet.getName());
         }
 
-    }   
-    
+    }
+
     PutDataSetTopLevelDataSetHandler(PutDataSetService service,
             ITopLevelDataSetRegistrator registrator, String sessionToken, NewDataSetDTO newDataSet,
             InputStream inputStream)
@@ -178,14 +177,6 @@ class PutDataSetTopLevelDataSetHandler
      */
     public List<DataSetInformation> execute() throws UserFailureException, IOException
     {
-        // Check that the session owner has at least user access to the space the new data
-        // set should belongs to
-        SpaceIdentifier spaceId = getSpaceIdentifierForNewDataSet();
-        if (spaceId != null)
-        {
-            getOpenBisService().checkSpaceAccess(sessionToken, spaceId);
-        }
-
         writeDataSetToTempDirectory();
 
         // Register the data set
@@ -203,18 +194,9 @@ class PutDataSetTopLevelDataSetHandler
 
     /**
      * Run the put command; this method assumes the data set is already in the rpc-icoming folder in the share.
-     * 
      */
     public List<DataSetInformation> executeWithoutWriting() throws UserFailureException
     {
-        // Check that the session owner has at least user access to the space the new data
-        // set should belongs to
-        SpaceIdentifier spaceId = getSpaceIdentifierForNewDataSet();
-        if (spaceId != null)
-        {
-            getOpenBisService().checkSpaceAccess(sessionToken, spaceId);
-        }
-
         // Register the data set
         try
         {
@@ -362,51 +344,6 @@ class PutDataSetTopLevelDataSetHandler
         }
     }
 
-    private SpaceIdentifier getSpaceIdentifierForNewDataSet()
-    {
-        SpaceIdentifier spaceId = null;
-        DataSetOwner owner = getDataSetOwner();
-        if (owner != null)
-        {
-            switch (owner.getType())
-            {
-                case EXPERIMENT:
-                    ExperimentIdentifier experimentId = tryExperimentIdentifier();
-                    spaceId =
-                            new SpaceIdentifier(experimentId.getSpaceCode());
-                    break;
-                case SAMPLE:
-                    SampleIdentifier sampleId = trySampleIdentifier();
-                    spaceId = sampleId.getSpaceLevel();
-                    break;
-                case DATA_SET:
-                    String dataSetCode = tryGetDataSetCode();
-
-                    AbstractExternalData parentDataSet = getOpenBisService().tryGetDataSet(dataSetCode);
-                    if (parentDataSet != null)
-                    {
-                        if (parentDataSet.getExperiment() != null)
-                        {
-                            experimentId =
-                                    ExperimentIdentifierFactory.parse(parentDataSet.getExperiment()
-                                            .getIdentifier());
-                            spaceId =
-                                    new SpaceIdentifier(experimentId.getSpaceCode());
-                        }
-                        if (parentDataSet.getSample() != null)
-                        {
-                            sampleId =
-                                    SampleIdentifierFactory.parse(parentDataSet.getSample()
-                                            .getIdentifier());
-                            spaceId = sampleId.getSpaceLevel();
-                        }
-                    }
-                    break;
-            }
-        }
-        return spaceId;
-    }
-
     private ExperimentIdentifier tryExperimentIdentifier()
     {
         DataSetOwner owner = getDataSetOwner();
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetSessionAuthorizer.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetSessionAuthorizer.java
index 135f6273d81..bae92be8965 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetSessionAuthorizer.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetSessionAuthorizer.java
@@ -144,7 +144,8 @@ public class DatasetSessionAuthorizer implements IDssSessionAuthorizer
         {
             operationLog.info(String.format(
                     "Checking whether space '%s' is writable to session '%s' on "
-                            + "openBIS application server.", spaceId, sessionToken));
+                            + "openBIS application server.",
+                    spaceId, sessionToken));
         }
         final IEncapsulatedOpenBISService openBISService = ServiceProvider.getOpenBISService();
 
@@ -158,6 +159,50 @@ public class DatasetSessionAuthorizer implements IDssSessionAuthorizer
         }
     }
 
+    @Override
+    public Status checkExperimentWriteable(String sessionToken, String experimentIdentifier)
+    {
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog.info(String.format(
+                    "Checking whether experiment '%s' is writable to session '%s' on "
+                            + "openBIS application server.",
+                    experimentIdentifier, sessionToken));
+        }
+        final IEncapsulatedOpenBISService openBISService = ServiceProvider.getOpenBISService();
+
+        try
+        {
+            openBISService.checkExperimentAccess(sessionToken, experimentIdentifier);
+            return Status.OK;
+        } catch (UserFailureException ex)
+        {
+            return Status.createError(ex.getMessage());
+        }
+    }
+
+    @Override
+    public Status checkSampleWriteable(String sessionToken, String sampleIdentifier)
+    {
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog.info(String.format(
+                    "Checking whether sample '%s' is writable to session '%s' on "
+                            + "openBIS application server.",
+                    sampleIdentifier, sessionToken));
+        }
+        final IEncapsulatedOpenBISService openBISService = ServiceProvider.getOpenBISService();
+
+        try
+        {
+            openBISService.checkSampleAccess(sessionToken, sampleIdentifier);
+            return Status.OK;
+        } catch (UserFailureException ex)
+        {
+            return Status.createError(ex.getMessage());
+        }
+    }
+
     @Override
     public Status checkInstanceAdminAuthorization(String sessionToken)
     {
@@ -165,7 +210,8 @@ public class DatasetSessionAuthorizer implements IDssSessionAuthorizer
         {
             operationLog.info(String.format(
                     "Checking if session '%s' has instance admin privileges on "
-                            + "openBIS application server.", sessionToken));
+                            + "openBIS application server.",
+                    sessionToken));
         }
         final IEncapsulatedOpenBISService openBISService = ServiceProvider.getOpenBISService();
 
@@ -186,7 +232,8 @@ public class DatasetSessionAuthorizer implements IDssSessionAuthorizer
         {
             operationLog.info(String.format(
                     "Checking if session '%s' has space power user privileges on "
-                            + "openBIS application server.", sessionToken));
+                            + "openBIS application server.",
+                    sessionToken));
         }
         final IEncapsulatedOpenBISService openBISService = ServiceProvider.getOpenBISService();
 
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java
index 7d25e9465d8..7802e90993f 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java
@@ -647,6 +647,18 @@ public final class EncapsulatedOpenBISService implements IEncapsulatedOpenBISSer
         service.checkSpaceAccess(sToken, spaceId);
     }
 
+    @Override
+    public void checkExperimentAccess(String sToken, String experimentIdentifier)
+    {
+        service.checkExperimentAccess(sToken, experimentIdentifier);
+    }
+
+    @Override
+    public void checkSampleAccess(String sToken, String sampleIdentifier)
+    {
+        service.checkSampleAccess(sToken, sampleIdentifier);
+    }
+
     @Override
     public List<DataSetShareId> listDataSetShareIds() throws UserFailureException
     {
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java
index 548021c7223..8a30b6d010e 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java
@@ -408,6 +408,14 @@ public interface IEncapsulatedOpenBISService extends IEncapsulatedBasicOpenBISSe
     @ManagedAuthentication
     public void checkSpaceAccess(String sToken, SpaceIdentifier spaceId);
 
+    /** See {@link IServiceForDataStoreServer#checkExperimentAccess(String, String)} */
+    @ManagedAuthentication
+    public void checkExperimentAccess(String sToken, String experimentIdentifier);
+
+    /** See {@link IServiceForDataStoreServer#checkSampleAccess(String, String)} */
+    @ManagedAuthentication
+    public void checkSampleAccess(String sToken, String sampleIdentifier);
+
     /**
      * See {@link IServiceForDataStoreServer#tryAuthenticate(String, String)}
      * 
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DssSessionAuthorizationHolder.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DssSessionAuthorizationHolder.java
index c96fed5f2da..83cea33178f 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DssSessionAuthorizationHolder.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DssSessionAuthorizationHolder.java
@@ -52,6 +52,18 @@ public class DssSessionAuthorizationHolder
                 return Status.createError("Data set authorizer not set.");
             }
 
+            @Override
+            public Status checkExperimentWriteable(String sessionToken, String experimentIdentifier)
+            {
+                return Status.createError("Data set authorizer not set.");
+            }
+
+            @Override
+            public Status checkSampleWriteable(String sessionToken, String sampleIdentifier)
+            {
+                return Status.createError("Data set authorizer not set.");
+            }
+
             @Override
             public Status checkInstanceAdminAuthorization(String sessionToken)
             {
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/IDssSessionAuthorizer.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/IDssSessionAuthorizer.java
index d3b24c7a377..ad86877372b 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/IDssSessionAuthorizer.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/IDssSessionAuthorizer.java
@@ -51,6 +51,20 @@ public interface IDssSessionAuthorizer
      */
     public Status checkSpaceWriteable(String sessionToken, SpaceIdentifier spaceId);
 
+    /**
+     * Checks whether the session identified by <var>sessionToken</var> is authorized to write to the given <var>experimentIdentifier</var>.
+     * 
+     * @return {@link Status#OK} if the access is granted, an error status otherwise.
+     */
+    public Status checkExperimentWriteable(String sessionToken, String experimentIdentifier);
+
+    /**
+     * Checks whether the session identified by <var>sessionToken</var> is authorized to write to the given <var>sampleIdentifier</var>.
+     * 
+     * @return {@link Status#OK} if the access is granted, an error status otherwise.
+     */
+    public Status checkSampleWriteable(String sessionToken, String sampleIdentifier);
+
     /**
      * Checks whether the session identified by <var>sessionToken</var> has openBIS instance admin privileges.
      * 
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/NewDataSetPredicate.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/NewDataSetPredicate.java
index eb47706f80d..9ccc324f364 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/NewDataSetPredicate.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/NewDataSetPredicate.java
@@ -25,11 +25,6 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v1.authorization
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.IDssServiceRpcGeneric;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.v1.NewDataSetDTO.DataSetOwner;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 
 /**
  * Predicate for checking that the new data set can be registered (i.e., user has access to the space for the new data set).
@@ -54,25 +49,15 @@ public class NewDataSetPredicate implements
     {
         DataSetOwner owner = newDataSet.getDataSetOwner();
         String ownerIdentifier = owner.getIdentifier();
-        SpaceIdentifier spaceId;
+
         switch (owner.getType())
         {
             case EXPERIMENT:
-                ExperimentIdentifier experimentId =
-                        new ExperimentIdentifierFactory(ownerIdentifier).createIdentifier();
-                spaceId =
-                        new SpaceIdentifier(experimentId.getSpaceCode());
-                return DssSessionAuthorizationHolder.getAuthorizer().checkSpaceWriteable(
-                        sessionToken, spaceId);
+                return DssSessionAuthorizationHolder.getAuthorizer().checkExperimentWriteable(sessionToken, ownerIdentifier);
             case SAMPLE:
-                SampleIdentifier sampleId =
-                        new SampleIdentifierFactory(ownerIdentifier).createIdentifier();
-                spaceId = sampleId.getSpaceLevel();
-                return DssSessionAuthorizationHolder.getAuthorizer().checkSpaceWriteable(
-                        sessionToken, spaceId);
+                return DssSessionAuthorizationHolder.getAuthorizer().checkSampleWriteable(sessionToken, ownerIdentifier);
             case DATA_SET:
-                return DssSessionAuthorizationHolder.getAuthorizer().checkDatasetAccess(
-                        sessionToken, ownerIdentifier);
+                return DssSessionAuthorizationHolder.getAuthorizer().checkDatasetAccess(sessionToken, ownerIdentifier);
         }
 
         return null; // impossible!
diff --git a/datastore_server/sourceTest/core-plugins/generic-test/1/dss/drop-boxes/test/data-set-handler.py b/datastore_server/sourceTest/core-plugins/generic-test/1/dss/drop-boxes/test/data-set-handler.py
index 141afa7c684..b2c12740de0 100644
--- a/datastore_server/sourceTest/core-plugins/generic-test/1/dss/drop-boxes/test/data-set-handler.py
+++ b/datastore_server/sourceTest/core-plugins/generic-test/1/dss/drop-boxes/test/data-set-handler.py
@@ -3,24 +3,26 @@ from java.lang import IllegalArgumentException
 transaction = service.transaction(incoming)
 
 
-
-#test for LMS-2879
-sample = transaction.getSample("/CISD/DYNA-TEST-1")    
-sa = transaction.getSampleForUpdate(sample.getSampleIdentifier())
-
-sa.setPropertyValue('COMMENT', 'comment')
-#try:
-
-#this set should fail. It doesn't as a leftover from LMS-2879
-sa.setPropertyValue('DYNAMIC_DESCRIPTION', 'description')
-#raise 'Setting of dynamic property should result in an exception'
-#except IllegalArgumentException, isx:
-#print isx
-#ok
+if incoming.getPath().endswith("-with-dyna-test"):
+    print ">>>>>>> dyna test <<<<<<<"
+    #test for LMS-2879
+    sample = transaction.getSample("/CISD/DYNA-TEST-1")    
+    sa = transaction.getSampleForUpdate(sample.getSampleIdentifier())
+    
+    sa.setPropertyValue('COMMENT', 'comment')
+    #try:
+    
+    #this set should fail. It doesn't as a leftover from LMS-2879
+    sa.setPropertyValue('DYNAMIC_DESCRIPTION', 'description')
+    #raise 'Setting of dynamic property should result in an exception'
+    #except IllegalArgumentException, isx:
+    #print isx
+    #ok
 
 dataSet = transaction.createNewDataSet()
 exp = dataSet.getExperiment()
 samp = dataSet.getSample()
+
 if exp is None and samp is None:
   raise IllegalArgumentException("data-set-handler.py: No Experiment or Sample specified")
 transaction.moveFile(incoming.getAbsolutePath(), dataSet)
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/OpenbisServiceFacadeTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/OpenbisServiceFacadeTest.java
index f50d9bc9220..02eaf824068 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/OpenbisServiceFacadeTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/OpenbisServiceFacadeTest.java
@@ -56,6 +56,7 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria.MatchCl
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria.MatchClauseAttribute;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SimpleDataSetInformationDTO;
 import ch.systemsx.cisd.openbis.generic.shared.util.TestInstanceHostUtils;
+import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 
 /**
  * @author Chandrasekhar Ramakrishnan
@@ -87,7 +88,69 @@ public class OpenbisServiceFacadeTest extends SystemTestCase
         File exampleDataSet = new File(workingDirectory, "my-data");
         NewDataSetDTO newDataset = createNewDataSetDTO(exampleDataSet);
         DataSet dataSet = serviceFacade.putDataSet(newDataset, exampleDataSet);
-        checkDataSet(dataSet);
+        checkDataSet(dataSet, "my-data");
+    }
+
+    @Test
+    public void testPutDataSetWithDynamicPropertyTest() throws Exception
+    {
+        File exampleDataSet = new File(workingDirectory, "my-data-with-dyna-test");
+        NewDataSetDTO newDataset = createNewDataSetDTO(exampleDataSet);
+        DataSet dataSet = serviceFacade.putDataSet(newDataset, exampleDataSet);
+        checkDataSet(dataSet, "my-data-with-dyna-test");
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testPutDataSetWithExperimentWithProjectAuthorization(ProjectAuthorizationUser user) throws IOException
+    {
+        IOpenbisServiceFacade userServiceFacade = createServiceFacade(user.getUserId());
+
+        File exampleDataSet = new File(workingDirectory, "my-data-pa");
+        DataSetOwner dataSetOwner = new DataSetOwner(DataSetOwnerType.EXPERIMENT, "/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST");
+        NewDataSetDTO newDataset = createNewDataSetDTO(exampleDataSet, dataSetOwner);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            DataSet dataSet = userServiceFacade.putDataSet(newDataset, exampleDataSet);
+            assertNotNull(dataSet);
+        } else
+        {
+            try
+            {
+                userServiceFacade.putDataSet(newDataset, exampleDataSet);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testPutDataSetWithSampleWithProjectAuthorization(ProjectAuthorizationUser user) throws IOException
+    {
+        IOpenbisServiceFacade userServiceFacade = createServiceFacade(user.getUserId());
+
+        File exampleDataSet = new File(workingDirectory, "my-data-pa");
+
+        DataSetOwner dataSetOwner = new DataSetOwner(DataSetOwnerType.SAMPLE, "/TEST-SPACE/EV-TEST");
+        NewDataSetDTO newDataset = createNewDataSetDTO(exampleDataSet, dataSetOwner);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            DataSet dataSet = userServiceFacade.putDataSet(newDataset, exampleDataSet);
+            assertNotNull(dataSet);
+        } else
+        {
+            try
+            {
+                userServiceFacade.putDataSet(newDataset, exampleDataSet);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
     }
 
     @Test
@@ -99,7 +162,7 @@ public class OpenbisServiceFacadeTest extends SystemTestCase
         NewDataSetDTO newDataset = createNewDataSetDTO(exampleDataSet);
         newDataset.setParentDataSetCodes(Arrays.asList(code));
         DataSet dataSet = serviceFacade.putDataSet(newDataset, exampleDataSet);
-        checkDataSet(dataSet);
+        checkDataSet(dataSet, "my-data");
 
         // We need to take a different route to get the data set we just registered to check if it
         // has a parent.
@@ -331,6 +394,11 @@ public class OpenbisServiceFacadeTest extends SystemTestCase
     {
         DataSetOwner dataSetOwner =
                 new DataSetOwner(DataSetOwnerType.SAMPLE, "/CISD/CP-TEST-1");
+        return createNewDataSetDTO(exampleDataSet, dataSetOwner);
+    }
+
+    private NewDataSetDTO createNewDataSetDTO(File exampleDataSet, DataSetOwner dataSetOwner) throws IOException
+    {
         exampleDataSet.mkdirs();
         FileUtilities.writeToFile(new File(exampleDataSet, "data.log"), "hello world");
         FileUtilities.writeToFile(new File(exampleDataSet, "data-set.properties"),
@@ -384,11 +452,11 @@ public class OpenbisServiceFacadeTest extends SystemTestCase
         return dataSets.get(0);
     }
 
-    private void checkDataSet(DataSet dataSet) throws IOException
+    private void checkDataSet(DataSet dataSet, String folderName) throws IOException
     {
-        assertEquals("hello world", getContent(dataSet, "data.log"));
-        assertEquals("1 2 3", getContent(dataSet, "data/1.data"));
-        assertEquals("4 5 6 7", getContent(dataSet, "data/2.data"));
+        assertEquals("hello world", getContent(dataSet, folderName + "/data.log"));
+        assertEquals("1 2 3", getContent(dataSet, folderName + "/data/1.data"));
+        assertEquals("4 5 6 7", getContent(dataSet, folderName + "/data/2.data"));
     }
 
     private String getContent(DataSet dataSet, String path) throws IOException
@@ -397,7 +465,7 @@ public class OpenbisServiceFacadeTest extends SystemTestCase
         InputStream inputStream = null;
         try
         {
-            inputStream = dataSet.getFile("/original/my-data/" + path);
+            inputStream = dataSet.getFile("/original/" + path);
             IOUtils.copy(inputStream, output);
         } finally
         {
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateSystemTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateSystemTest.java
new file mode 100644
index 00000000000..1c42fc05b2a
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateSystemTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 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.datastoreserver.systemtests.authorization.predicate.entity;
+
+import java.util.List;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.ProjectAuthorizationUser;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTest;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestAssertions;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestAssertionsDelegate;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.systemtest.authorization.predicate.entity.EntityPredicateTestService;
+
+/**
+ * @author pkupczyk
+ */
+public abstract class AtomicOperationsPredicateSystemTest extends CommonPredicateSystemTest<AtomicEntityOperationDetails>
+{
+
+    @Override
+    protected void evaluateObjects(ProjectAuthorizationUser user, List<AtomicEntityOperationDetails> objects, Object param)
+    {
+        getBean(EntityPredicateTestService.class).testAtomicOperationsPredicate(user.getSessionProvider(), objects.get(0));
+    }
+
+    @Override
+    protected CommonPredicateSystemTestAssertions<AtomicEntityOperationDetails> getAssertions()
+    {
+        return new CommonPredicateSystemTestAssertionsDelegate<AtomicEntityOperationDetails>(super.getAssertions())
+            {
+                @Override
+                public void assertWithNullObject(ProjectAuthorizationUser user, Throwable t, Object param)
+                {
+                    if (user.isDisabledProjectUser())
+                    {
+                        assertAuthorizationFailureExceptionThatNoRoles(t);
+                    } else
+                    {
+                        assertException(t, UserFailureException.class, "No atomic entity operations specified.");
+                    }
+                }
+            };
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithDataSetRegistrationSystemTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithDataSetRegistrationSystemTest.java
new file mode 100644
index 00000000000..00abeb3847e
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithDataSetRegistrationSystemTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017 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.datastoreserver.systemtests.authorization.predicate.entity;
+
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.common.ExperimentIdentifierUtil;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.common.SampleIdentifierUtil;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestAssertions;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestDataSetAssertions;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.IdentifierHelper;
+
+/**
+ * @author pkupczyk
+ */
+public class AtomicOperationsPredicateWithDataSetRegistrationSystemTest extends AtomicOperationsPredicateSystemTest
+{
+
+    @Override
+    public Object[] getParams()
+    {
+        return getDataSetKinds();
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createNonexistentObject(Object param)
+    {
+        NewExternalData newDataSet = new NewExternalData();
+
+        switch ((DataSetKind) param)
+        {
+            case EXPERIMENT:
+                newDataSet.setExperimentIdentifierOrNull(ExperimentIdentifierUtil.createNonexistentObject(null));
+                break;
+            case SPACE_SAMPLE:
+                newDataSet.setSampleIdentifierOrNull(SampleIdentifierUtil.createNonexistentObject(SampleKind.SPACE));
+                break;
+            case PROJECT_SAMPLE:
+                newDataSet.setSampleIdentifierOrNull(SampleIdentifierUtil.createNonexistentObject(SampleKind.PROJECT));
+                break;
+            case EXPERIMENT_SAMPLE:
+                newDataSet.setSampleIdentifierOrNull(SampleIdentifierUtil.createNonexistentObject(SampleKind.EXPERIMENT));
+                break;
+            default:
+                throw new RuntimeException();
+        }
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.dataSet(newDataSet);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createObject(SpacePE spacePE, ProjectPE projectPE, Object param)
+    {
+        DataPE dataSet = getDataSet(spacePE, projectPE, (DataSetKind) param);
+        NewExternalData newDataSet = new NewExternalData();
+
+        if (dataSet.getExperiment() != null)
+        {
+            newDataSet.setExperimentIdentifierOrNull(IdentifierHelper.createExperimentIdentifier(dataSet.getExperiment()));
+        }
+
+        if (dataSet.tryGetSample() != null)
+        {
+            newDataSet.setSampleIdentifierOrNull(IdentifierHelper.createSampleIdentifier(dataSet.tryGetSample()));
+        }
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.dataSet(newDataSet);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected CommonPredicateSystemTestAssertions<AtomicEntityOperationDetails> getAssertions()
+    {
+        return new CommonPredicateSystemTestDataSetAssertions<AtomicEntityOperationDetails>(super.getAssertions());
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithDataSetUpdateSystemTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithDataSetUpdateSystemTest.java
new file mode 100644
index 00000000000..80416748172
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithDataSetUpdateSystemTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2017 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.datastoreserver.systemtests.authorization.predicate.entity;
+
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.ProjectAuthorizationUser;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.common.ExperimentIdentifierUtil;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.common.SampleIdentifierUtil;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestAssertions;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestDataSetAssertions;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetBatchUpdatesDTO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.IdentifierHelper;
+
+/**
+ * @author pkupczyk
+ */
+public class AtomicOperationsPredicateWithDataSetUpdateSystemTest extends AtomicOperationsPredicateSystemTest
+{
+
+    @Override
+    public Object[] getParams()
+    {
+        return getDataSetKinds();
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createNonexistentObject(Object param)
+    {
+        DataSetBatchUpdatesDTO update = new DataSetBatchUpdatesDTO();
+
+        switch ((DataSetKind) param)
+        {
+            case EXPERIMENT:
+                update.setExperimentIdentifierOrNull(ExperimentIdentifierUtil.createNonexistentObject(null));
+                break;
+            case SPACE_SAMPLE:
+                update.setSampleIdentifierOrNull(SampleIdentifierUtil.createNonexistentObject(SampleKind.SPACE));
+                break;
+            case PROJECT_SAMPLE:
+                update.setSampleIdentifierOrNull(SampleIdentifierUtil.createNonexistentObject(SampleKind.PROJECT));
+                break;
+            case EXPERIMENT_SAMPLE:
+                update.setSampleIdentifierOrNull(SampleIdentifierUtil.createNonexistentObject(SampleKind.EXPERIMENT));
+                break;
+            default:
+                throw new RuntimeException();
+        }
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.dataSetUpdate(update);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createObject(SpacePE spacePE, ProjectPE projectPE, Object param)
+    {
+        DataPE dataSet = getDataSet(spacePE, projectPE, (DataSetKind) param);
+        DataSetBatchUpdatesDTO update = new DataSetBatchUpdatesDTO();
+
+        if (dataSet.getExperiment() != null)
+        {
+            update.setExperimentIdentifierOrNull(IdentifierHelper.createExperimentIdentifier(dataSet.getExperiment()));
+        }
+
+        if (dataSet.tryGetSample() != null)
+        {
+            update.setSampleIdentifierOrNull(IdentifierHelper.createSampleIdentifier(dataSet.tryGetSample()));
+        }
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.dataSetUpdate(update);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected CommonPredicateSystemTestAssertions<AtomicEntityOperationDetails> getAssertions()
+    {
+        return new CommonPredicateSystemTestDataSetAssertions<AtomicEntityOperationDetails>(super.getAssertions())
+            {
+                @Override
+                public void assertWithNonexistentObject(ProjectAuthorizationUser user, Throwable t, Object param)
+                {
+                    if (user.isDisabledProjectUser())
+                    {
+                        assertAuthorizationFailureExceptionThatNoRoles(t);
+                    } else if (user.isInstanceUser())
+                    {
+                        assertNoException(t);
+                    } else
+                    {
+                        assertAuthorizationFailureExceptionThatNotEnoughPrivileges(t);
+                    }
+                }
+            };
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithExperimentRegistrationSystemTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithExperimentRegistrationSystemTest.java
new file mode 100644
index 00000000000..9fe9ddcf3a0
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithExperimentRegistrationSystemTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 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.datastoreserver.systemtests.authorization.predicate.entity;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
+
+/**
+ * @author pkupczyk
+ */
+public class AtomicOperationsPredicateWithExperimentRegistrationSystemTest extends AtomicOperationsPredicateSystemTest
+{
+
+    @Override
+    protected AtomicEntityOperationDetails createNonexistentObject(Object param)
+    {
+        NewExperiment newExperiment = new NewExperiment("/IDONTEXIST/IDONTEXIST/IDONTEXIST", "idontexist");
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.experiment(newExperiment);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createObject(SpacePE spacePE, ProjectPE projectPE, Object param)
+    {
+        NewExperiment newExperiment = new NewExperiment("/" + spacePE.getCode() + "/" + projectPE.getCode() + "/NEW_EXPERIMENT", "testType");
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.experiment(newExperiment);
+
+        return builder.getDetails();
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithExperimentUpdateSystemTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithExperimentUpdateSystemTest.java
new file mode 100644
index 00000000000..450cbf05bfd
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithExperimentUpdateSystemTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2017 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.datastoreserver.systemtests.authorization.predicate.entity;
+
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.ProjectAuthorizationUser;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestAssertions;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestAssertionsDelegate;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentUpdatesDTO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
+
+/**
+ * @author pkupczyk
+ */
+public class AtomicOperationsPredicateWithExperimentUpdateSystemTest extends AtomicOperationsPredicateSystemTest
+{
+
+    @Override
+    protected AtomicEntityOperationDetails createNonexistentObject(Object param)
+    {
+        ExperimentUpdatesDTO update = new ExperimentUpdatesDTO();
+        update.setExperimentId(new TechId(-1));
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.experimentUpdate(update);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createObject(SpacePE spacePE, ProjectPE projectPE, Object param)
+    {
+        ExperimentPE experimentPE = getExperiment(spacePE, projectPE);
+
+        ExperimentUpdatesDTO update = new ExperimentUpdatesDTO();
+        update.setExperimentId(new TechId(experimentPE.getId()));
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.experimentUpdate(update);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected CommonPredicateSystemTestAssertions<AtomicEntityOperationDetails> getAssertions()
+    {
+        return new CommonPredicateSystemTestAssertionsDelegate<AtomicEntityOperationDetails>(super.getAssertions())
+            {
+                @Override
+                public void assertWithNonexistentObject(ProjectAuthorizationUser user, Throwable t, Object param)
+                {
+                    if (user.isDisabledProjectUser())
+                    {
+                        assertAuthorizationFailureExceptionThatNoRoles(t);
+                    } else if (user.isInstanceUser())
+                    {
+                        assertNoException(t);
+                    } else
+                    {
+                        assertUserFailureExceptionThatExperimentDoesNotExist(t);
+                    }
+                }
+            };
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithProjectRegistrationSystemTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithProjectRegistrationSystemTest.java
new file mode 100644
index 00000000000..5a039aadf77
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithProjectRegistrationSystemTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 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.datastoreserver.systemtests.authorization.predicate.entity;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewProject;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
+
+/**
+ * @author pkupczyk
+ */
+public class AtomicOperationsPredicateWithProjectRegistrationSystemTest extends AtomicOperationsPredicateSystemTest
+{
+
+    @Override
+    protected AtomicEntityOperationDetails createNonexistentObject(Object param)
+    {
+        NewProject newProject = new NewProject("/IDONTEXIST/IDONTEXIST", "idontexist");
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.project(newProject);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createObject(SpacePE spacePE, ProjectPE projectPE, Object param)
+    {
+        NewProject newProject = new NewProject("/" + spacePE.getCode() + "/" + projectPE.getCode(), "description");
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.project(newProject);
+
+        return builder.getDetails();
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithProjectUpdateSystemTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithProjectUpdateSystemTest.java
new file mode 100644
index 00000000000..7e7903395e9
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithProjectUpdateSystemTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2017 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.datastoreserver.systemtests.authorization.predicate.entity;
+
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.ProjectAuthorizationUser;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestAssertions;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestAssertionsDelegate;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectUpdatesDTO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
+
+/**
+ * @author pkupczyk
+ */
+public class AtomicOperationsPredicateWithProjectUpdateSystemTest extends AtomicOperationsPredicateSystemTest
+{
+
+    @Override
+    protected AtomicEntityOperationDetails createNonexistentObject(Object param)
+    {
+        ProjectUpdatesDTO update = new ProjectUpdatesDTO();
+        update.setIdentifier("/IDONTEXIST/IDONTEXIST");
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.projectUpdate(update);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createObject(SpacePE spacePE, ProjectPE projectPE, Object param)
+    {
+        ProjectUpdatesDTO update = new ProjectUpdatesDTO();
+        update.setIdentifier("/" + spacePE.getCode() + "/" + projectPE.getCode());
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.projectUpdate(update);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected CommonPredicateSystemTestAssertions<AtomicEntityOperationDetails> getAssertions()
+    {
+        return new CommonPredicateSystemTestAssertionsDelegate<AtomicEntityOperationDetails>(super.getAssertions())
+            {
+                @Override
+                public void assertWithNonexistentObject(ProjectAuthorizationUser user, Throwable t, Object param)
+                {
+                    if (user.isDisabledProjectUser())
+                    {
+                        assertAuthorizationFailureExceptionThatNoRoles(t);
+                    } else if (user.isInstanceUser())
+                    {
+                        assertNoException(t);
+                    } else
+                    {
+                        assertAuthorizationFailureExceptionThatNotEnoughPrivileges(t);
+                    }
+                }
+            };
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithSampleRegistrationSystemTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithSampleRegistrationSystemTest.java
new file mode 100644
index 00000000000..8931fb0f341
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithSampleRegistrationSystemTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2017 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.datastoreserver.systemtests.authorization.predicate.entity;
+
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.ProjectAuthorizationUser;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.common.SampleIdentifierUtil;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestAssertions;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestSampleAssertions;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+
+/**
+ * @author pkupczyk
+ */
+public class AtomicOperationsPredicateWithSampleRegistrationSystemTest extends AtomicOperationsPredicateSystemTest
+{
+
+    @Override
+    public Object[] getParams()
+    {
+        return getSampleKinds(SampleKind.SHARED_READ_WRITE);
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createNonexistentObject(Object param)
+    {
+        SampleIdentifier identifier = SampleIdentifierUtil.createNonexistentObject(param);
+        NewSample newSample = new NewSample();
+        newSample.setIdentifier(identifier.toString());
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.sample(newSample);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createObject(SpacePE spacePE, ProjectPE projectPE, Object param)
+    {
+        SampleIdentifier identifier = SampleIdentifierUtil.createObject(this, spacePE, projectPE, param);
+        NewSample newSample = new NewSample();
+        newSample.setIdentifier(identifier.toString());
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.sample(newSample);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected CommonPredicateSystemTestAssertions<AtomicEntityOperationDetails> getAssertions()
+    {
+        return new CommonPredicateSystemTestSampleAssertions<AtomicEntityOperationDetails>(super.getAssertions())
+            {
+                @Override
+                public void assertWithNonexistentObject(ProjectAuthorizationUser user, Throwable t, Object param)
+                {
+                    if (user.isDisabledProjectUser())
+                    {
+                        assertAuthorizationFailureExceptionThatNoRoles(t);
+                    } else if (SampleKind.SHARED_READ_WRITE.equals(param) && false == user.isInstanceUser())
+                    {
+                        assertAuthorizationFailureExceptionThatNotEnoughPrivileges(t);
+                    } else
+                    {
+                        assertNoException(t);
+                    }
+                }
+            };
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithSampleUpdateSystemTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithSampleUpdateSystemTest.java
new file mode 100644
index 00000000000..b150e312396
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/predicate/entity/AtomicOperationsPredicateWithSampleUpdateSystemTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017 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.datastoreserver.systemtests.authorization.predicate.entity;
+
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.ProjectAuthorizationUser;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.common.SampleIdentifierUtil;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestAssertions;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.predicate.CommonPredicateSystemTestSampleAssertions;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+
+/**
+ * @author pkupczyk
+ */
+public class AtomicOperationsPredicateWithSampleUpdateSystemTest extends AtomicOperationsPredicateSystemTest
+{
+
+    @Override
+    public Object[] getParams()
+    {
+        return getSampleKinds(SampleKind.SHARED_READ_WRITE);
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createNonexistentObject(Object param)
+    {
+        SampleIdentifier identifier = SampleIdentifierUtil.createNonexistentObject(param);
+        SampleUpdatesDTO update = new SampleUpdatesDTO(null, null, null, null, null, 0, identifier, null, null);
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.sampleUpdate(update);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected AtomicEntityOperationDetails createObject(SpacePE spacePE, ProjectPE projectPE, Object param)
+    {
+        SampleIdentifier identifier = SampleIdentifierUtil.createObject(this, spacePE, projectPE, param);
+        SampleUpdatesDTO update = new SampleUpdatesDTO(null, null, null, null, null, 0, identifier, null, null);
+
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.sampleUpdate(update);
+
+        return builder.getDetails();
+    }
+
+    @Override
+    protected CommonPredicateSystemTestAssertions<AtomicEntityOperationDetails> getAssertions()
+    {
+        return new CommonPredicateSystemTestSampleAssertions<AtomicEntityOperationDetails>(super.getAssertions())
+            {
+                @Override
+                public void assertWithNonexistentObject(ProjectAuthorizationUser user, Throwable t, Object param)
+                {
+                    if (user.isDisabledProjectUser())
+                    {
+                        assertAuthorizationFailureExceptionThatNoRoles(t);
+                    } else if (user.isInstanceUser())
+                    {
+                        assertNoException(t);
+                    } else
+                    {
+                        assertAuthorizationFailureExceptionThatNotEnoughPrivileges(t);
+                    }
+                }
+            };
+    }
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/validator/deletion/DeletionValidatorWithDataSetSystemTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/validator/deletion/DeletionValidatorWithDataSetSystemTest.java
new file mode 100644
index 00000000000..b821cde3935
--- /dev/null
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/authorization/validator/deletion/DeletionValidatorWithDataSetSystemTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 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.datastoreserver.systemtests.authorization.validator.deletion;
+
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.validator.CommonValidatorSystemTestAssertions;
+import ch.systemsx.cisd.openbis.datastoreserver.systemtests.authorization.validator.CommonValidatorSystemTestDataSetAssertions;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
+
+/**
+ * @author pkupczyk
+ */
+public class DeletionValidatorWithDataSetSystemTest extends DeletionValidatorSystemTest
+{
+
+    @Override
+    public Object[] getParams()
+    {
+        return getDataSetKinds();
+    }
+
+    @Override
+    protected Deletion createObject(SpacePE spacePE, ProjectPE projectPE, Object param)
+    {
+        DataPE dataSet = getDataSet(spacePE, projectPE, (DataSetKind) param);
+        return getCommonService().trashDataSet(dataSet);
+    }
+
+    @Override
+    protected CommonValidatorSystemTestAssertions<Deletion> getAssertions()
+    {
+        return new CommonValidatorSystemTestDataSetAssertions<Deletion>(super.getAssertions());
+    }
+
+}
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 9de55dcf7ab..49e3f94ba45 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
@@ -92,8 +92,8 @@ import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.ProjectId
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.ProjectIdentifierPredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.ProjectPermIdPredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SampleAugmentedCodePredicate;
+import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SampleAugmentedCodeReadWritePredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SampleIdentifierPredicate;
-import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SampleOwnerIdentifierPredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SamplePermIdPredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SamplePermIdStringPredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SampleTechIdPredicate;
@@ -1082,7 +1082,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
     @Override
     @RolesAllowed(RoleWithHierarchy.SPACE_ETL_SERVER)
     public void registerDataSet(final String sessionToken,
-            @AuthorizationGuard(guardClass = SampleOwnerIdentifierPredicate.class)
+            @AuthorizationGuard(guardClass = SampleIdentifierPredicate.class)
             final SampleIdentifier sampleIdentifier, final NewExternalData externalData)
             throws UserFailureException
     {
@@ -1344,6 +1344,24 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
         // do nothing, the access rights specified in method annotations are checked by a proxy
     }
 
+    @Override
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
+    public void checkExperimentAccess(String sessionToken,
+            @AuthorizationGuard(guardClass = ExperimentAugmentedCodePredicate.class) String experimentIdentifier)
+    {
+        checkSession(sessionToken);
+        // do nothing, the access rights specified in method annotations are checked by a proxy
+    }
+
+    @Override
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
+    public void checkSampleAccess(String sessionToken,
+            @AuthorizationGuard(guardClass = SampleAugmentedCodeReadWritePredicate.class) String sampleIdentifier)
+    {
+        checkSession(sessionToken);
+        // do nothing, the access rights specified in method annotations are checked by a proxy
+    }
+
     @Override
     @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @ReturnValueFilter(validatorClass = SampleValidator.class)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServerLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServerLogger.java
index b6185a3fe85..1217acc1113 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServerLogger.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServerLogger.java
@@ -343,6 +343,18 @@ public class ServiceForDataStoreServerLogger extends AbstractServerLogger implem
         logAccess(sessionToken, "checkSpaceAccess", "SPACE(%s)", spaceId);
     }
 
+    @Override
+    public void checkExperimentAccess(String sessionToken, String experimentIdentifier)
+    {
+        logAccess(sessionToken, "checkExperimentAccess", "EXPERIMENT(%s)", experimentIdentifier);
+    }
+
+    @Override
+    public void checkSampleAccess(String sessionToken, String sampleIdentifier)
+    {
+        logAccess(sessionToken, "checkSampleAccess", "SAMPLE(%s)", sampleIdentifier);
+    }
+
     @Override
     public IDatasetLocationNode tryGetDataSetLocation(String sessionToken, String dataSetCode)
             throws UserFailureException
@@ -422,10 +434,11 @@ public class ServiceForDataStoreServerLogger extends AbstractServerLogger implem
     public List<SimpleDataSetInformationDTO> listPhysicalDataSetsByArchivingStatus(String sessionToken, String dataStoreCode,
             DataSetArchivingStatus archivingStatus, Boolean presentInArchive) throws UserFailureException
     {
-        logAccess(sessionToken, "listPhysicalDataSetsByArchivingStatus", "DATA_STORE(%s) STATUS(%s) PRESENT(%s)", dataStoreCode, archivingStatus, presentInArchive);
+        logAccess(sessionToken, "listPhysicalDataSetsByArchivingStatus", "DATA_STORE(%s) STATUS(%s) PRESENT(%s)", dataStoreCode, archivingStatus,
+                presentInArchive);
         return null;
     }
-    
+
     @Override
     public List<SimpleDataSetInformationDTO> listPhysicalDataSetsWithUnknownSize(String sessionToken, String dataStoreCode, int chunkSize,
             String dataSetCodeLowerLimit)
@@ -476,7 +489,8 @@ public class ServiceForDataStoreServerLogger extends AbstractServerLogger implem
     {
         logAccess(Level.DEBUG, sessionToken, "listDeletedDataSets", "LAST_SEEN_EVENT(%s)",
                 (lastSeenDeletionEventIdOrNull == null ? "all" : "id > "
-                        + lastSeenDeletionEventIdOrNull), (maxDeletionDateOrNull == null ? "all"
+                        + lastSeenDeletionEventIdOrNull),
+                (maxDeletionDateOrNull == null ? "all"
                         : "maxDeletionDate > " + maxDeletionDateOrNull));
         return null;
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/AtomicOperationsPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/AtomicOperationsPredicate.java
index 9e84daed0ea..79001e7a408 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/AtomicOperationsPredicate.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/AtomicOperationsPredicate.java
@@ -50,9 +50,9 @@ public class AtomicOperationsPredicate extends AbstractPredicate<AtomicEntityOpe
 
     private final SampleUpdatesCollectionPredicate sampleUpdatesPredicate;
 
-    private final SampleOwnerIdentifierPredicate sampleOwnerIdentifierPredicate;
+    private final SampleIdentifierPredicate sampleIdentifierPredicate;
 
-    private final ExistingSpaceIdentifierPredicate experimentOwnerIdentifierPredicate;
+    private final ExperimentAugmentedCodePredicate experimentIdentifierPredicate;
 
     private final DataSetUpdatesCollectionPredicate dataSetUpdatesCollectionPredicate;
 
@@ -66,8 +66,8 @@ public class AtomicOperationsPredicate extends AbstractPredicate<AtomicEntityOpe
         experimentUpdatesPredicate = new ExperimentUpdatesPredicate();
         newSamplePredicate = new NewSamplePredicate();
         sampleUpdatesPredicate = new SampleUpdatesCollectionPredicate();
-        sampleOwnerIdentifierPredicate = new SampleOwnerIdentifierPredicate(true, true);
-        experimentOwnerIdentifierPredicate = new ExistingSpaceIdentifierPredicate();
+        sampleIdentifierPredicate = new SampleIdentifierPredicate(true, true);
+        experimentIdentifierPredicate = new ExperimentAugmentedCodePredicate(true);
         dataSetUpdatesCollectionPredicate = new DataSetUpdatesCollectionPredicate();
         newProjectPredicate = new NewProjectPredicate();
         projectUpdatePredicate = new ProjectUpdatesPredicate();
@@ -80,8 +80,8 @@ public class AtomicOperationsPredicate extends AbstractPredicate<AtomicEntityOpe
         experimentUpdatesPredicate.init(provider);
         newSamplePredicate.init(provider);
         sampleUpdatesPredicate.init(provider);
-        sampleOwnerIdentifierPredicate.init(provider);
-        experimentOwnerIdentifierPredicate.init(provider);
+        sampleIdentifierPredicate.init(provider);
+        experimentIdentifierPredicate.init(provider);
         dataSetUpdatesCollectionPredicate.init(provider);
         newProjectPredicate.init(provider);
         projectUpdatePredicate.init(provider);
@@ -375,13 +375,13 @@ public class AtomicOperationsPredicate extends AbstractPredicate<AtomicEntityOpe
             if (null != sampleIdentifier)
             {
                 status =
-                        predicate.sampleOwnerIdentifierPredicate.doEvaluation(person, allowedRoles,
+                        predicate.sampleIdentifierPredicate.doEvaluation(person, allowedRoles,
                                 sampleIdentifier);
             } else
             {
                 status =
-                        predicate.experimentOwnerIdentifierPredicate.doEvaluation(person,
-                                allowedRoles, experimentIdentifier);
+                        predicate.experimentIdentifierPredicate.doEvaluation(person,
+                                allowedRoles, experimentIdentifier != null ? experimentIdentifier.toString() : null);
             }
             return status;
         }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/ExistingSampleOwnerIdentifierPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleAugmentedCodeReadWritePredicate.java
similarity index 68%
rename from openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/ExistingSampleOwnerIdentifierPredicate.java
rename to openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleAugmentedCodeReadWritePredicate.java
index 2d8a080ac3f..cadf55e55a0 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/ExistingSampleOwnerIdentifierPredicate.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleAugmentedCodeReadWritePredicate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 ETH Zuerich, CISD
+ * 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.
@@ -17,14 +17,14 @@
 package ch.systemsx.cisd.openbis.generic.server.authorization.predicate;
 
 /**
- * A {@link SampleOwnerIdentifierPredicate} which evaluates to OK if the space does not exist.
+ * @author pkupczyk
  */
-public final class ExistingSampleOwnerIdentifierPredicate extends SampleOwnerIdentifierPredicate
+public class SampleAugmentedCodeReadWritePredicate extends SampleAugmentedCodePredicate
 {
 
-    public ExistingSampleOwnerIdentifierPredicate()
+    public SampleAugmentedCodeReadWritePredicate()
     {
-        super(true, true);
+        super(false);
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleIdentifierPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleIdentifierPredicate.java
index a111345b7a5..09c3a764e52 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleIdentifierPredicate.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleIdentifierPredicate.java
@@ -154,6 +154,11 @@ public class SampleIdentifierPredicate extends AbstractPredicate<SampleIdentifie
         String spaceCode = SpaceCodeHelper.getSpaceCode(person, value.getSpaceLevel());
         String sampleCode = value.getSampleCode();
 
+        if (sampleCode == null)
+        {
+            return Status.createError();
+        }
+
         IProjectAuthorization<SpaceCodeAndSampleCode> pa = new ProjectAuthorizationBuilder<SpaceCodeAndSampleCode>()
                 .withData(dataProvider)
                 .withUser(new UserProviderFromPersonPE(person))
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleListPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleListPredicate.java
index addab097aab..62a67fa1a9d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleListPredicate.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleListPredicate.java
@@ -37,8 +37,8 @@ import ch.systemsx.cisd.openbis.generic.server.authorization.project.provider.ro
 import ch.systemsx.cisd.openbis.generic.server.authorization.project.provider.user.UserProviderFromPersonPE;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleOwnerIdentifier;
 
 import net.lemnik.eodsql.BaseQuery;
 import net.lemnik.eodsql.QueryTool;
@@ -60,18 +60,19 @@ public class SampleListPredicate extends AbstractSpacePredicate<List<Sample>>
     public static interface ISampleToSpaceQuery extends BaseQuery
     {
         @Select(sql = "select distinct sp.code from samples sa inner join spaces sp on sa.space_id = sp.id where sa.id = any(?{1}) "
-                + "union select distinct sp.code from samples sa inner join spaces sp on sa.space_id = sp.id where sa.perm_id = any(?{2})", parameterBindings = { LongArrayMapper.class,
+                + "union select distinct sp.code from samples sa inner join spaces sp on sa.space_id = sp.id where sa.perm_id = any(?{2})", parameterBindings = {
+                        LongArrayMapper.class,
                         StringArrayMapper.class })
         public List<String> getSampleSpaceCodes(long[] sampleIds, String[] samplePermIds);
     }
 
-    private final SampleOwnerIdentifierPredicate idOwnerPredicate;
+    private final SampleIdentifierPredicate sampleIdentifierPredicate;
 
     private final ISampleToSpaceQuery sampleToSpaceQuery;
 
     public SampleListPredicate()
     {
-        idOwnerPredicate = new SampleOwnerIdentifierPredicate();
+        sampleIdentifierPredicate = new SampleIdentifierPredicate();
         sampleToSpaceQuery = QueryTool.getManagedQuery(ISampleToSpaceQuery.class);
     }
 
@@ -83,7 +84,7 @@ public class SampleListPredicate extends AbstractSpacePredicate<List<Sample>>
     public final void init(IAuthorizationDataProvider provider)
     {
         super.init(provider);
-        idOwnerPredicate.init(provider);
+        sampleIdentifierPredicate.init(provider);
     }
 
     @Override
@@ -141,9 +142,9 @@ public class SampleListPredicate extends AbstractSpacePredicate<List<Sample>>
                 }
             }
 
-            final SampleOwnerIdentifier idOwner =
+            final SampleIdentifier sampleIdentifier =
                     SampleIdentifierFactory.parse(sample.getIdentifier());
-            final Status status = idOwnerPredicate.evaluate(person, allowedRoles, idOwner);
+            final Status status = sampleIdentifierPredicate.evaluate(person, allowedRoles, sampleIdentifier);
             if (Status.OK.equals(status) == false)
             {
                 return status;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleOwnerIdentifierPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleOwnerIdentifierPredicate.java
deleted file mode 100644
index 76e99479087..00000000000
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleOwnerIdentifierPredicate.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2008 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.authorization.predicate;
-
-import java.util.List;
-
-import ch.systemsx.cisd.common.exceptions.Status;
-import ch.systemsx.cisd.openbis.generic.server.authorization.IAuthorizationDataProvider;
-import ch.systemsx.cisd.openbis.generic.server.authorization.RoleWithIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleOwnerIdentifier;
-
-/**
- * An <code>IPredicate</code> implementation based on {@link SampleOwnerIdentifier}.
- * 
- * @author Christian Ribeaud
- */
-public class SampleOwnerIdentifierPredicate extends AbstractPredicate<SampleOwnerIdentifier>
-{
-    private final SpaceIdentifierPredicate spacePredicate;
-
-    private final DatabaseInstanceIdentifierPredicate databaseInstanceIdentifierPredicate;
-
-    boolean initialized;
-
-    public SampleOwnerIdentifierPredicate()
-    {
-        this(true, false);
-    }
-
-    public SampleOwnerIdentifierPredicate(boolean isReadAccess)
-    {
-        this(isReadAccess, false);
-    }
-
-    public SampleOwnerIdentifierPredicate(boolean isReadAccess, boolean okForNonExistentSpaces)
-    {
-        spacePredicate = new SpaceIdentifierPredicate(okForNonExistentSpaces);
-        databaseInstanceIdentifierPredicate = new DatabaseInstanceIdentifierPredicate(isReadAccess);
-    }
-
-    //
-    // AbstractPredicate
-    //
-
-    @Override
-    public final void init(IAuthorizationDataProvider provider)
-    {
-        assert initialized == false;
-        spacePredicate.init(provider);
-        databaseInstanceIdentifierPredicate.init(provider);
-        initialized = true;
-    }
-
-    @Override
-    public final String getCandidateDescription()
-    {
-        return "sample identifier";
-    }
-
-    @Override
-    protected final Status doEvaluation(final PersonPE person,
-            final List<RoleWithIdentifier> allowedRoles, final SampleOwnerIdentifier value)
-    {
-        return performEvaluation(person, allowedRoles, value);
-    }
-
-    /**
-     * @deprecated exposed only for usage in screening api authorization - use 'doEvaluation()' in other places
-     */
-    @Deprecated
-    public Status performEvaluation(final PersonPE person,
-            final List<RoleWithIdentifier> allowedRoles, final SampleOwnerIdentifier value)
-    {
-        // Skip all further checks if the person has instance-wide write permissions.
-        if (hasInstanceWritePermissions(person, allowedRoles).isOK())
-        {
-            return Status.OK;
-        }
-
-        if (value.isDatabaseInstanceLevel())
-        {
-            return databaseInstanceIdentifierPredicate.doEvaluation(person, allowedRoles, null);
-        } else
-        {
-            return spacePredicate.doEvaluation(person, allowedRoles, value.getSpaceLevel());
-        }
-    }
-
-}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/EntityOperationChecker.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/EntityOperationChecker.java
index 66d3cef23c3..06ab06838b9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/EntityOperationChecker.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/EntityOperationChecker.java
@@ -20,7 +20,7 @@ import java.util.List;
 
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IAuthSession;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleOwnerIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 
 /**
  * @author pkupczyk
@@ -36,7 +36,7 @@ public class EntityOperationChecker implements IEntityOperationChecker
 
     @Override
     public void assertInstanceSampleUpdateAllowed(IAuthSession session,
-            List<? extends SampleOwnerIdentifier> instanceSamples)
+            List<? extends SampleIdentifier> instanceSamples)
     {
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/IEntityOperationChecker.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/IEntityOperationChecker.java
index 85c0fc2d75e..da2ba2cee3c 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/IEntityOperationChecker.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/IEntityOperationChecker.java
@@ -21,11 +21,11 @@ import java.util.List;
 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;
-import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SampleOwnerIdentifierPredicate;
+import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SampleIdentifierPredicate;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IAuthSession;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleOwnerIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 
 /**
  * @author pkupczyk
@@ -41,6 +41,6 @@ public interface IEntityOperationChecker
     @RolesAllowed(
     { RoleWithHierarchy.INSTANCE_ADMIN, RoleWithHierarchy.INSTANCE_ETL_SERVER })
     public void assertInstanceSampleUpdateAllowed(IAuthSession session,
-            @AuthorizationGuard(guardClass = SampleOwnerIdentifierPredicate.class) List<? extends SampleOwnerIdentifier> instanceSamples);
+            @AuthorizationGuard(guardClass = SampleIdentifierPredicate.class) List<? extends SampleIdentifier> instanceSamples);
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java
index fab96e1d340..aae2e5adf7e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java
@@ -250,7 +250,7 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
         }
         return experimentPE;
     }
-    
+
     private ProjectPE tryFindProject(Map<String, ProjectPE> projectCache, ProjectIdentifier projectIdentifier)
     {
         if (projectIdentifier == null)
@@ -259,8 +259,8 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
         }
         return tryFindProject(projectCache, projectIdentifier.toString(), null);
     }
-    
-    private ProjectPE tryFindProject(Map<String, ProjectPE> projectCache, String projectIdentifier, 
+
+    private ProjectPE tryFindProject(Map<String, ProjectPE> projectCache, String projectIdentifier,
             String defaultSpace)
     {
         if (projectIdentifier == null)
@@ -608,7 +608,7 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
 
         assignSampleAndRelatedDataSetsToExperiment(sample, newExperiment);
     }
-    
+
     protected void updateProject(SamplePE sample, ProjectIdentifier projectIdentifierOrNull,
             Map<String, ProjectPE> projectCache)
     {
@@ -633,7 +633,7 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
                     sample.getIdentifier());
         }
     }
-    
+
     private void ensureSampleAttachableToExperiment(SamplePE sample, ExperimentPE newExperiment)
     {
         if (sample.getSpace() == null && newExperiment != null)
@@ -883,7 +883,7 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
 
     protected void assertInstanceSampleUpdateAllowed(List<? extends SamplePE> samples)
     {
-        List<SampleOwnerIdentifier> instanceSamples = new ArrayList<SampleOwnerIdentifier>();
+        List<SampleIdentifier> instanceSamples = new ArrayList<SampleIdentifier>();
 
         for (SamplePE sample : samples)
         {
@@ -891,7 +891,7 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
 
             if (sampleIdentifier.isDatabaseInstanceLevel())
             {
-                instanceSamples.add(sampleIdentifier.createSampleOwnerIdentifier());
+                instanceSamples.add(sampleIdentifier);
             }
         }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IServiceForDataStoreServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IServiceForDataStoreServer.java
index 0f34c083d3a..1f0fd587950 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IServiceForDataStoreServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IServiceForDataStoreServer.java
@@ -586,6 +586,24 @@ public interface IServiceForDataStoreServer extends IServer, ISessionProvider
     @Transactional(readOnly = true)
     public void checkSpaceAccess(String sessionToken, SpaceIdentifier spaceId);
 
+    /**
+     * Check if the user has USER access on the experiment
+     * 
+     * @param sessionToken The user's session token.
+     * @param experimentIdentifier The identifier for the experiment the user wants to access
+     */
+    @Transactional(readOnly = true)
+    public void checkExperimentAccess(String sessionToken, String experimentIdentifier);
+
+    /**
+     * Check if the user has USER access on the sample
+     * 
+     * @param sessionToken The user's session token.
+     * @param sampleIdentifier The identifier for the sample the user wants to access
+     */
+    @Transactional(readOnly = true)
+    public void checkSampleAccess(String sessionToken, String sampleIdentifier);
+
     /**
      * Returns a list of unique codes for the specified entity kind.
      */
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleOwnerIdentifierPredicateTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleOwnerIdentifierPredicateTest.java
deleted file mode 100644
index 15c832531b7..00000000000
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/SampleOwnerIdentifierPredicateTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2008 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.authorization.predicate;
-
-import java.util.List;
-
-import org.testng.annotations.Test;
-
-import ch.systemsx.cisd.common.exceptions.Status;
-import ch.systemsx.cisd.openbis.generic.server.authorization.AuthorizationTestCase;
-import ch.systemsx.cisd.openbis.generic.server.authorization.RoleWithIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleOwnerIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
-
-/**
- * @author Franz-Josef Elmer
- */
-public class SampleOwnerIdentifierPredicateTest extends AuthorizationTestCase
-{
-    @Test
-    public void testAllowedToModifyDatabase()
-    {
-        SampleOwnerIdentifierPredicate predicate = new SampleOwnerIdentifierPredicate(false);
-        PersonPE person = createPerson();
-        List<RoleWithIdentifier> roles = createRoles(true);
-        SampleOwnerIdentifier identifier = new SampleOwnerIdentifier();
-        prepareProvider(createSpaces());
-        predicate.init(provider);
-
-        Status status = predicate.evaluate(person, roles, identifier);
-
-        assertEquals(false, status.isError());
-        context.assertIsSatisfied();
-    }
-
-    @Test
-    public void testNotAllowedToModifyDatabase()
-    {
-        SampleOwnerIdentifierPredicate predicate = new SampleOwnerIdentifierPredicate(false);
-        PersonPE person = createPerson();
-        List<RoleWithIdentifier> roles = createRoles(false);
-        SampleOwnerIdentifier identifier = new SampleOwnerIdentifier();
-        prepareProvider(createSpaces());
-        predicate.init(provider);
-
-        Status status = predicate.evaluate(person, roles, identifier);
-
-        assertEquals(true, status.isError());
-        assertEquals("User 'megapixel' does not have enough privileges to modify "
-                + "instance level entities.", status.tryGetErrorMessage());
-        context.assertIsSatisfied();
-    }
-
-    @Test
-    public void testAllowedDatabaseInstance()
-    {
-        SampleOwnerIdentifierPredicate predicate = new SampleOwnerIdentifierPredicate();
-        PersonPE person = createPerson();
-        List<RoleWithIdentifier> roles = createRoles(false);
-        SampleOwnerIdentifier identifier = new SampleOwnerIdentifier();
-        prepareProvider(createSpaces());
-        predicate.init(provider);
-
-        Status status = predicate.evaluate(person, roles, identifier);
-
-        assertEquals(false, status.isError());
-        context.assertIsSatisfied();
-    }
-
-    @Test
-    public void testGenericAllowedDatabaseInstance()
-    {
-        SampleOwnerIdentifierPredicate predicate = new SampleOwnerIdentifierPredicate();
-        PersonPE person = createPerson();
-        List<RoleWithIdentifier> roles = createRoles(false);
-        SampleOwnerIdentifier identifier = new SampleOwnerIdentifier();
-        prepareProvider(createSpaces());
-        predicate.init(provider);
-
-        Status status = predicate.evaluate(person, roles, identifier);
-
-        assertEquals(Status.OK, status);
-        context.assertIsSatisfied();
-    }
-
-    @Test
-    public void testAllowedSpace()
-    {
-        SampleOwnerIdentifierPredicate predicate = new SampleOwnerIdentifierPredicate();
-        PersonPE person = createPerson();
-        List<RoleWithIdentifier> roles = createRoles(false);
-        SampleOwnerIdentifier identifier =
-                new SampleOwnerIdentifier(new SpaceIdentifier(SPACE_CODE));
-        prepareProvider(createSpaces());
-        predicate.init(provider);
-
-        Status status = predicate.evaluate(person, roles, identifier);
-
-        assertEquals(false, status.isError());
-        context.assertIsSatisfied();
-    }
-
-    @Test
-    public void testNotAllowedSpace()
-    {
-        SampleOwnerIdentifierPredicate predicate = new SampleOwnerIdentifierPredicate();
-        PersonPE person = createPerson();
-        List<RoleWithIdentifier> roles = createRoles(false);
-        SampleOwnerIdentifier identifier =
-                new SampleOwnerIdentifier(new SpaceIdentifier(ANOTHER_SPACE_CODE));
-        prepareProvider(createSpaces());
-        predicate.init(provider);
-
-        Status status = predicate.evaluate(person, roles, identifier);
-
-        assertEquals(true, status.isError());
-        assertEquals("User 'megapixel' does not have enough privileges.", status
-                .tryGetErrorMessage());
-        context.assertIsSatisfied();
-    }
-}
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/authorization/predicate/entity/EntityPredicateTestService.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/authorization/predicate/entity/EntityPredicateTestService.java
index 382401d1761..13bd819f0a2 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/authorization/predicate/entity/EntityPredicateTestService.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/authorization/predicate/entity/EntityPredicateTestService.java
@@ -21,9 +21,11 @@ import org.springframework.transaction.annotation.Transactional;
 
 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.AtomicOperationsPredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.BasicEntityDescriptionPredicate;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.BasicEntityDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IAuthSessionProvider;
 
 /**
@@ -40,4 +42,11 @@ public class EntityPredicateTestService
     {
     }
 
+    @Transactional
+    @RolesAllowed(value = { RoleWithHierarchy.PROJECT_OBSERVER })
+    public void testAtomicOperationsPredicate(IAuthSessionProvider sessionProvider,
+            @AuthorizationGuard(guardClass = AtomicOperationsPredicate.class) AtomicEntityOperationDetails operation)
+    {
+    }
+
 }
-- 
GitLab