From 07795b3ccce52fa349721d429f8f594537d82629 Mon Sep 17 00:00:00 2001
From: pkupczyk <pkupczyk>
Date: Fri, 1 Sep 2017 18:48:40 +0000
Subject: [PATCH] SSDM-5619 : Project Authorization - modify @RolesAllowed
 annotations at data set related methods

SVN: 38693
---
 .../systemtest/api/v3/ArchiveDataSetTest.java |  27 +
 .../api/v3/UnarchiveDataSetTest.java          |  31 +
 .../dataset/DataSetAuthorizationExecutor.java |  14 +-
 .../FileFormatTypeAuthorizationExecutor.java  |   2 +-
 .../LocatorTypeAuthorizationExecutor.java     |   2 +-
 .../StorageFormatAuthorizationExecutor.java   |   2 +-
 .../UpdateDataSetPropertyExecutor.java        |   2 +-
 .../DataStoreAuthorizationExecutor.java       |   4 +-
 .../ExternalDmsAuthorizationExecutor.java     |   4 +-
 .../VocabularyTermAuthorizationExecutor.java  |   4 +-
 .../openbis/generic/server/CommonServer.java  |  82 +--
 .../server/IETLEntityOperationChecker.java    |   4 +-
 .../server/ServiceForDataStoreServer.java     |  20 +-
 .../v1/GeneralInformationChangingService.java |  12 +-
 .../api/v1/GeneralInformationService.java     |  19 +-
 .../NewSampleIdentifierPredicate.java         |  53 +-
 .../server/business/IRelationshipService.java |  10 +-
 .../business/bo/AbstractBusinessObject.java   |   5 +
 .../server/business/bo/MetaprojectBO.java     |  32 +-
 .../plugin/generic/server/GenericServer.java  |   8 +-
 .../asapi/v3/CreateDataSetTest.java           | 136 ++--
 .../asapi/v3/DeleteDataSetTest.java           |  33 +-
 .../systemtest/asapi/v3/GetDataSetTest.java   |  25 +
 .../asapi/v3/SearchDataSetTest.java           |  27 +
 .../asapi/v3/UpdateDataSetTest.java           |  26 +
 .../server/ServiceForDataStoreServerTest.java | 250 +++++++-
 .../server/GenericServerDatabaseTest.java     | 109 +++-
 .../openbis/systemtest/CommonServerTest.java  | 599 +++++++++++++++++-
 ...GeneralInformationChangingServiceTest.java | 328 +++++++++-
 .../api/v1/GeneralInformationServiceTest.java | 294 ++++++++-
 30 files changed, 1975 insertions(+), 189 deletions(-)

diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/ArchiveDataSetTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/ArchiveDataSetTest.java
index bff15b09eb1..06f5c0cc851 100644
--- a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/ArchiveDataSetTest.java
+++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/ArchiveDataSetTest.java
@@ -23,7 +23,10 @@ import org.testng.annotations.Test;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.ArchivingStatus;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.archive.DataSetArchiveOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
+import ch.systemsx.cisd.common.exceptions.AuthorizationFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 
 /**
  * @author pkupczyk
@@ -84,4 +87,28 @@ public class ArchiveDataSetTest extends AbstractArchiveUnarchiveDataSetTest
         waitUntilDataSetStatus(dataSetCode, ArchivingStatus.AVAILABLE);
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testArchiveWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String sessionToken = v3.login(user.getUserId(), PASSWORD);
+
+        IDataSetId dataSetId = new DataSetPermId("20120628092259000-41");
+        DataSetArchiveOptions options = new DataSetArchiveOptions();
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            v3.archiveDataSets(sessionToken, Arrays.asList(dataSetId), options);
+        } else
+        {
+            try
+            {
+                v3.archiveDataSets(sessionToken, Arrays.asList(dataSetId), options);
+                fail();
+            } catch (Exception e)
+            {
+                assertEquals(e.getCause().getClass(), AuthorizationFailureException.class);
+            }
+        }
+    }
+
 }
diff --git a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UnarchiveDataSetTest.java b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UnarchiveDataSetTest.java
index c084caf9e09..3a4de65d493 100644
--- a/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UnarchiveDataSetTest.java
+++ b/datastore_server/sourceTest/java/ch/ethz/sis/openbis/generic/dss/systemtest/api/v3/UnarchiveDataSetTest.java
@@ -23,8 +23,11 @@ import org.testng.annotations.Test;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.ArchivingStatus;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.archive.DataSetArchiveOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.unarchive.DataSetUnarchiveOptions;
+import ch.systemsx.cisd.common.exceptions.AuthorizationFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 
 /**
  * @author pkupczyk
@@ -72,4 +75,32 @@ public class UnarchiveDataSetTest extends AbstractArchiveUnarchiveDataSetTest
         waitUntilDataSetStatus(dataSetCode, ArchivingStatus.AVAILABLE);
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testUnarchiveWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String adminSessionToken = v3.login(TEST_USER, PASSWORD);
+        String sessionToken = v3.login(user.getUserId(), PASSWORD);
+
+        IDataSetId dataSetId = new DataSetPermId("20120628092259000-41");
+        DataSetArchiveOptions archiveOptions = new DataSetArchiveOptions();
+        DataSetUnarchiveOptions unarchiveOptions = new DataSetUnarchiveOptions();
+
+        v3.archiveDataSets(adminSessionToken, Arrays.asList(dataSetId), archiveOptions);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            v3.unarchiveDataSets(sessionToken, Arrays.asList(dataSetId), unarchiveOptions);
+        } else
+        {
+            try
+            {
+                v3.unarchiveDataSets(sessionToken, Arrays.asList(dataSetId), unarchiveOptions);
+                fail();
+            } catch (Exception e)
+            {
+                assertEquals(e.getCause().getClass(), AuthorizationFailureException.class);
+            }
+        }
+    }
+
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/DataSetAuthorizationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/DataSetAuthorizationExecutor.java
index a640ad16e1f..697c272b6f5 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/DataSetAuthorizationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/DataSetAuthorizationExecutor.java
@@ -62,7 +62,7 @@ public class DataSetAuthorizationExecutor implements IDataSetAuthorizationExecut
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("CREATE_DATASET")
     @DatabaseCreateOrDeleteModification(value = ObjectKind.DATA_SET)
     public void canCreate(IOperationContext context, @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE dataSet)
@@ -102,7 +102,7 @@ public class DataSetAuthorizationExecutor implements IDataSetAuthorizationExecut
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("UPDATE_DATASET")
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     public void canUpdate(IOperationContext context, IDataSetId id, @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE dataSet)
@@ -128,7 +128,7 @@ public class DataSetAuthorizationExecutor implements IDataSetAuthorizationExecut
 
     @Override
     @DatabaseCreateOrDeleteModification(value = { ObjectKind.DATA_SET, ObjectKind.DELETION })
-    @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("DELETE_DATASET")
     public void canDelete(IOperationContext context, IDataSetId id, @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE dataSet)
     {
@@ -136,28 +136,28 @@ public class DataSetAuthorizationExecutor implements IDataSetAuthorizationExecut
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("GET_DATASET")
     public void canGet(IOperationContext context)
     {
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("SEARCH_DATASET")
     public void canSearch(IOperationContext context)
     {
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("ARCHIVE_DATASET")
     public void canArchive(IOperationContext context, IDataSetId id, @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE dataSet)
     {
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("UNARCHIVE_DATASET")
     public void canUnarchive(IOperationContext context, IDataSetId id, @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE dataSet)
     {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/FileFormatTypeAuthorizationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/FileFormatTypeAuthorizationExecutor.java
index ab133f78620..cdb9ef0250d 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/FileFormatTypeAuthorizationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/FileFormatTypeAuthorizationExecutor.java
@@ -31,7 +31,7 @@ public class FileFormatTypeAuthorizationExecutor implements IFileFormatTypeAutho
 {
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("GET_FILE_FORMAT_TYPE")
     public void canGet(IOperationContext context)
     {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/LocatorTypeAuthorizationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/LocatorTypeAuthorizationExecutor.java
index 2e1bea3fd58..0e82720a2cd 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/LocatorTypeAuthorizationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/LocatorTypeAuthorizationExecutor.java
@@ -31,7 +31,7 @@ public class LocatorTypeAuthorizationExecutor implements ILocatorTypeAuthorizati
 {
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("GET_LOCATOR_TYPE")
     public void canGet(IOperationContext context)
     {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/StorageFormatAuthorizationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/StorageFormatAuthorizationExecutor.java
index 9498a4b19d4..80efc364164 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/StorageFormatAuthorizationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/StorageFormatAuthorizationExecutor.java
@@ -31,7 +31,7 @@ public class StorageFormatAuthorizationExecutor implements IStorageFormatAuthori
 {
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("GET_STORAGE_FORMAT")
     public void canGet(IOperationContext context)
     {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/UpdateDataSetPropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/UpdateDataSetPropertyExecutor.java
index b5e6a0e088e..14fc4348d7c 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/UpdateDataSetPropertyExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/UpdateDataSetPropertyExecutor.java
@@ -39,7 +39,7 @@ public class UpdateDataSetPropertyExecutor implements IUpdateDataSetPropertyExec
     private IUpdateEntityPropertyExecutor executor;
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("UPDATE_DATASET_PROPERTY")
     public void update(IOperationContext context,
             MapBatch<? extends IPropertiesHolder, ? extends IEntityInformationWithPropertiesHolder> holderToEntityMap)
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/datastore/DataStoreAuthorizationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/datastore/DataStoreAuthorizationExecutor.java
index c6db2d127ef..8e7bc22748e 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/datastore/DataStoreAuthorizationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/datastore/DataStoreAuthorizationExecutor.java
@@ -31,14 +31,14 @@ public class DataStoreAuthorizationExecutor implements IDataStoreAuthorizationEx
 {
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("GET_DATASTORE")
     public void canGet(IOperationContext context)
     {
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("SEARCH_DATASTORE")
     public void canSearch(IOperationContext context)
     {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/externaldms/ExternalDmsAuthorizationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/externaldms/ExternalDmsAuthorizationExecutor.java
index 2bb479568ad..fbc91387ba8 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/externaldms/ExternalDmsAuthorizationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/externaldms/ExternalDmsAuthorizationExecutor.java
@@ -31,7 +31,7 @@ public class ExternalDmsAuthorizationExecutor implements IExternalDmsAuthorizati
 {
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("GET_EXTERNAL_DMS")
     public void canGet(IOperationContext context)
     {
@@ -50,7 +50,7 @@ public class ExternalDmsAuthorizationExecutor implements IExternalDmsAuthorizati
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     public void canSearch(IOperationContext context)
     {
     }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/VocabularyTermAuthorizationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/VocabularyTermAuthorizationExecutor.java
index 19e4d616037..e49f915b521 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/VocabularyTermAuthorizationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/vocabulary/VocabularyTermAuthorizationExecutor.java
@@ -110,14 +110,14 @@ public class VocabularyTermAuthorizationExecutor implements IVocabularyTermAutho
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("GET_VOCABULARY_TERM")
     public void canGet(IOperationContext context)
     {
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("SEARCH_VOCABULARY_TERM")
     public void canSearch(IOperationContext context)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
index fad70edeffb..6d87b019b7a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
@@ -560,7 +560,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     public List<SampleType> listSampleTypes(String sessionToken)
     {
         checkSession(sessionToken);
@@ -714,7 +714,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     @ReturnValueFilter(validatorClass = ExternalDataValidator.class)
     public List<AbstractExternalData> listSampleExternalData(final String sessionToken,
             @AuthorizationGuard(guardClass = SampleTechIdPredicate.class)
@@ -744,7 +744,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     public List<AbstractExternalData> listMetaprojectExternalData(final String sessionToken,
             final IMetaprojectId metaprojectId)
     {
@@ -773,7 +773,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
 
     // 'fast' implementation
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     @ReturnValueFilter(validatorClass = ExternalDataValidator.class)
     public List<AbstractExternalData> listDataSetRelationships(final String sessionToken,
             @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class)
@@ -1011,10 +1011,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public List<Experiment> listExperiments(final String sessionToken,
-            ExperimentType experimentType,
-            @AuthorizationGuard(guardClass = SpaceIdentifierPredicate.class) SpaceIdentifier spaceIdentifier)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
+    @ReturnValueFilter(validatorClass = ExperimentByIdentiferValidator.class)
+    public List<Experiment> listExperiments(final String sessionToken, ExperimentType experimentType, SpaceIdentifier spaceIdentifier)
     {
         return listExperiments(sessionToken, experimentType, spaceIdentifier, null, false, false);
     }
@@ -1648,7 +1647,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     @ReturnValueFilter(validatorClass = ExternalDataValidator.class)
     public List<AbstractExternalData> searchForDataSets(String sessionToken,
             DetailedSearchCriteria criteria)
@@ -1679,7 +1678,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
 
         final ExternalDataValidator validator = new ExternalDataValidator();
         validator.init(new AuthorizationDataProvider(getDAOFactory()));
-        
+
         final ArrayList<AbstractExternalData> datasets =
                 new ArrayList<AbstractExternalData>(unfilteredDatasets.size());
 
@@ -1694,7 +1693,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     public AbstractExternalData getDataSetInfo(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) TechId datasetId)
     {
@@ -1715,7 +1714,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_POWER_USER)
     @Capability("WRITE_DATASET")
     public DataSetUpdateResult updateDataSet(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetUpdatesPredicate.class) DataSetUpdatesDTO updates)
@@ -1734,7 +1733,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     @ReturnValueFilter(validatorClass = ExternalDataValidator.class)
     public List<AbstractExternalData> listRelatedDataSets(String sessionToken,
             DataSetRelatedEntities relatedEntities, boolean withDetails)
@@ -1767,7 +1766,6 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     @Override
     @RolesAllowed(RoleWithHierarchy.INSTANCE_OBSERVER)
     @Capability("SEARCH_ON_BEHALF_OF_USER")
-    @ReturnValueFilter(validatorClass = ExternalDataValidator.class)
     public List<AbstractExternalData> listRelatedDataSetsOnBehalfOfUser(String sessionToken,
             DataSetRelatedEntities relatedEntities, boolean withDetails, String userId)
     {
@@ -1791,14 +1789,24 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         Map<Long, Set<Metaproject>> translation =
                 MetaprojectTranslator.translateMetaprojectAssignments(assignments);
 
+        ExternalDataValidator validator = new ExternalDataValidator();
+        validator.init(new AuthorizationDataProvider(getDAOFactory()));
+
         final List<AbstractExternalData> list =
                 new ArrayList<AbstractExternalData>(resultSet.size());
         for (final DataPE hit : resultSet)
         {
             HibernateUtils.initialize(hit.getChildRelationships());
-            list.add(DataSetTranslator.translate(hit, session.getBaseIndexURL(), withDetails,
-                    translation.get(hit.getId()), managedPropertyEvaluatorFactory));
+
+            AbstractExternalData dataSet = DataSetTranslator.translate(hit, session.getBaseIndexURL(), withDetails,
+                    translation.get(hit.getId()), managedPropertyEvaluatorFactory);
+
+            if (validator.isValid(person, dataSet))
+            {
+                list.add(dataSet);
+            }
         }
+
         return list;
     }
 
@@ -2054,7 +2062,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_POWER_USER)
     @Capability("DELETE_DATASET")
     public void deleteDataSets(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> dataSetCodes, String reason, DeletionType type,
@@ -2366,8 +2374,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
-    public String uploadDataSets(String sessionToken, List<String> dataSetCodes,
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
+    public String uploadDataSets(String sessionToken,
+            @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> dataSetCodes,
             DataSetUploadContext uploadContext)
     {
         Session session = getSession(sessionToken);
@@ -3058,7 +3067,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     public TableModel createReportFromDatasets(String sessionToken,
             DatastoreServiceDescription serviceDescription,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes)
@@ -3070,7 +3079,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     public TableModel createReportFromDatasets(String sessionToken, String serviceKey,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes)
     {
@@ -3091,7 +3100,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     public void processDatasets(String sessionToken,
             DatastoreServiceDescription serviceDescription,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes)
@@ -3103,7 +3112,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_POWER_USER)
     @Capability("ARCHIVE_DATASET")
     public int archiveDatasets(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes, boolean removeFromDataStore)
@@ -3112,7 +3121,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     @Capability("UNARCHIVE_DATASET")
     public int unarchiveDatasets(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes)
@@ -3434,7 +3443,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_ADMIN)
     @Capability("LOCK_DATA_SETS")
     public int lockDatasets(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes)
@@ -3446,7 +3455,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_ADMIN)
     @Capability("UNLOCK_DATA_SETS")
     public int unlockDatasets(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> datasetCodes)
@@ -3458,7 +3467,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     public LinkModel retrieveLinkFromDataSet(String sessionToken,
             DatastoreServiceDescription serviceDescription,
             @AuthorizationGuard(guardClass = DataSetCodePredicate.class) String dataSetCode)
@@ -3659,13 +3668,14 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
-    public void updateManagedPropertyOnDataSet(String sessionToken, TechId experimentId,
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
+    public void updateManagedPropertyOnDataSet(String sessionToken,
+            @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) TechId dataSetId,
             IManagedProperty managedProperty, IManagedUiAction updateAction)
     {
         Session session = getSession(sessionToken);
         IDataBO dataSetBO = businessObjectFactory.createDataBO(session);
-        dataSetBO.loadDataByTechId(experimentId);
+        dataSetBO.loadDataByTechId(dataSetId);
 
         // Evaluate the script
         dataSetBO.enrichWithProperties();
@@ -3682,12 +3692,12 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
 
     @Override
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
-    public void updateManagedPropertyOnMaterial(String sessionToken, TechId experimentId,
+    public void updateManagedPropertyOnMaterial(String sessionToken, TechId materialId,
             IManagedProperty managedProperty, IManagedUiAction updateAction)
     {
         Session session = getSession(sessionToken);
         IMaterialBO materialBO = businessObjectFactory.createMaterialBO(session);
-        materialBO.loadDataByTechId(experimentId);
+        materialBO.loadDataByTechId(materialId);
 
         // Evaluate the script
         materialBO.enrichWithProperties();
@@ -3782,7 +3792,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     @Capability("WRITE_DATASET_PROPERTIES")
     public void updateDataSetProperties(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) TechId entityId, List<PropertyUpdates> modifiedProperties)
@@ -3909,7 +3919,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     @Capability("RESTORE")
     public void revertDeletions(final String sessionToken,
             @AuthorizationGuard(guardClass = RevertDeletionPredicate.class)
@@ -3963,7 +3973,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_ADMIN)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_ADMIN)
     @Capability("PURGE")
     public void deletePermanently(final String sessionToken,
             @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class)
@@ -4304,7 +4314,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     public void removeFromMetaproject(String sessionToken, IMetaprojectId metaprojectId,
             MetaprojectAssignmentsIds assignmentsToRemove)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/IETLEntityOperationChecker.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/IETLEntityOperationChecker.java
index 5a7ad5ab842..23d67488614 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/IETLEntityOperationChecker.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/IETLEntityOperationChecker.java
@@ -115,13 +115,13 @@ public interface IETLEntityOperationChecker
             @AuthorizationGuard(guardClass = SampleUpdatesCollectionPredicate.class) List<SampleUpdatesDTO> spaceSamples);
 
     @RolesAllowed(
-    { RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    { RoleWithHierarchy.PROJECT_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("CREATE_DATA_SETS_VIA_DSS")
     public void assertDataSetCreationAllowed(IAuthSession session,
             @AuthorizationGuard(guardClass = NewExternalDataPredicate.class) List<? extends NewExternalData> dataSets);
 
     @RolesAllowed(
-    { RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    { RoleWithHierarchy.PROJECT_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("UPDATE_DATA_SETS_VIA_DSS")
     public void assertDataSetUpdateAllowed(IAuthSession session,
             @AuthorizationGuard(guardClass = DataSetUpdatesCollectionPredicate.class) List<DataSetBatchUpdatesDTO> dataSets);
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 2316dc3786d..a823d5dfb3f 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
@@ -895,7 +895,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     public List<AbstractExternalData> listDataSetsByCode(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> dataSetCodes) throws UserFailureException
     {
@@ -1225,7 +1225,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
     }
 
     @Override
-    @RolesAllowed(value = { RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed(value = { RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     public IDatasetLocationNode tryGetDataSetLocation(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodePredicate.class) String dataSetCode) throws UserFailureException
     {
@@ -1238,8 +1238,9 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
     }
 
     @Override
-    @RolesAllowed(value = { RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    public AbstractExternalData tryGetLocalDataSet(String sessionToken, String dataSetCode,
+    @RolesAllowed(value = { RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    public AbstractExternalData tryGetLocalDataSet(String sessionToken,
+            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) String dataSetCode,
             String dataStore) throws UserFailureException
     {
         AbstractExternalData dataSet = tryGetDataSet(sessionToken, dataSetCode);
@@ -1251,7 +1252,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
     }
 
     @Override
-    @RolesAllowed(value = { RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed(value = { RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     public AbstractExternalData tryGetDataSet(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodePredicate.class) String dataSetCode) throws UserFailureException
     {
@@ -1279,8 +1280,9 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
     }
 
     @Override
-    @RolesAllowed(value = { RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    public AbstractExternalData tryGetThinDataSet(String sessionToken, String dataSetCode) throws UserFailureException
+    @RolesAllowed(value = { RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    public AbstractExternalData tryGetThinDataSet(String sessionToken,
+            @AuthorizationGuard(guardClass = DataSetCodePredicate.class) String dataSetCode) throws UserFailureException
     {
         assert sessionToken != null : "Unspecified session token.";
         assert dataSetCode != null : "Unspecified data set code.";
@@ -1315,7 +1317,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     public void checkDataSetAccess(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodePredicate.class) String dataSetCode) throws UserFailureException
     {
@@ -1324,7 +1326,7 @@ public class ServiceForDataStoreServer extends AbstractCommonServer<IServiceForD
     }
 
     @Override
-    @RolesAllowed({ RoleWithHierarchy.SPACE_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     public void checkDataSetCollectionAccess(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> dataSetCodes)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
index 36aee99039c..644a4fb2990 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
@@ -96,7 +96,7 @@ public class GeneralInformationChangingService extends
 
     @Override
     @Transactional
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     public void updateSampleProperties(String sessionToken, long sampleID,
             Map<String, String> properties)
     {
@@ -195,7 +195,7 @@ public class GeneralInformationChangingService extends
 
     @Override
     @Transactional(readOnly = false)
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     public void addToMetaproject(String sessionToken, IMetaprojectId metaprojectId,
             MetaprojectAssignmentsIds assignmentsToAdd)
     {
@@ -204,7 +204,7 @@ public class GeneralInformationChangingService extends
 
     @Override
     @Transactional(readOnly = false)
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     public void removeFromMetaproject(String sessionToken, IMetaprojectId metaprojectId,
             MetaprojectAssignmentsIds assignmentsToRemove)
     {
@@ -239,7 +239,7 @@ public class GeneralInformationChangingService extends
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     public final String registerSamples(
             final String sessionToken,
             final String sampleTypeCode,
@@ -256,7 +256,7 @@ public class GeneralInformationChangingService extends
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     public final String updateSamples(
             final String sessionToken,
             final String sampleTypeCode,
@@ -272,7 +272,7 @@ public class GeneralInformationChangingService extends
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     public final Map<String, Object> uploadedSamplesInfo(
             final String sessionToken,
             final String sampleTypeCode,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java
index b3a318f12a7..5dc1717a428 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java
@@ -47,6 +47,7 @@ import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Authoriz
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Capability;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.ReturnValueFilter;
 import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.DataSetCodeCollectionPredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.ExperimentAugmentedCodePredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.ExperimentIdPredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.ExperimentListPredicate;
@@ -479,7 +480,7 @@ public class GeneralInformationService extends AbstractServer<IGeneralInformatio
 
     @Override
     @Transactional(readOnly = true)
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     @ReturnValueFilter(validatorClass = DataSetByExperimentOrSampleIdentifierValidator.class)
     public List<DataSet> listDataSets(String sessionToken,
             @AuthorizationGuard(guardClass = SampleListPredicate.class) List<Sample> samples)
@@ -616,7 +617,7 @@ public class GeneralInformationService extends AbstractServer<IGeneralInformatio
 
     @Override
     @Transactional(readOnly = true)
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     @ReturnValueFilter(validatorClass = DataSetByExperimentOrSampleIdentifierValidator.class)
     public List<DataSet> listDataSetsForSample(String sessionToken,
             @AuthorizationGuard(guardClass = SamplePredicate.class) Sample sample, boolean areOnlyDirectlyConnectedIncluded)
@@ -762,7 +763,7 @@ public class GeneralInformationService extends AbstractServer<IGeneralInformatio
 
     @Override
     @Transactional(readOnly = true)
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     @ReturnValueFilter(validatorClass = DataSetByExperimentOrSampleIdentifierValidator.class)
     public List<DataSet> listDataSets(String sessionToken,
             @AuthorizationGuard(guardClass = SampleListPredicate.class) List<Sample> samples, EnumSet<Connections> connections)
@@ -883,9 +884,10 @@ public class GeneralInformationService extends AbstractServer<IGeneralInformatio
 
     @Override
     @Transactional(readOnly = true)
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     @ReturnValueFilter(validatorClass = DataSetByExperimentOrSampleIdentifierValidator.class)
-    public List<DataSet> getDataSetMetaData(String sessionToken, List<String> dataSetCodes)
+    public List<DataSet> getDataSetMetaData(String sessionToken,
+            @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> dataSetCodes)
     {
         return getDataSetMetaData(getSession(sessionToken), dataSetCodes, true);
     }
@@ -923,9 +925,10 @@ public class GeneralInformationService extends AbstractServer<IGeneralInformatio
 
     @Override
     @Transactional(readOnly = true)
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     @ReturnValueFilter(validatorClass = DataSetByExperimentOrSampleIdentifierValidator.class)
-    public List<DataSet> getDataSetMetaData(String sessionToken, List<String> dataSetCodes,
+    public List<DataSet> getDataSetMetaData(String sessionToken,
+            @AuthorizationGuard(guardClass = DataSetCodeCollectionPredicate.class) List<String> dataSetCodes,
             EnumSet<DataSetFetchOption> fetchOptions)
     {
         if (sessionToken == null)
@@ -1001,7 +1004,7 @@ public class GeneralInformationService extends AbstractServer<IGeneralInformatio
 
     @Override
     @Transactional(readOnly = true)
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     @ReturnValueFilter(validatorClass = DataSetByExperimentOrSampleIdentifierValidator.class)
     public List<DataSet> searchForDataSets(String sessionToken, SearchCriteria searchCriteria)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/NewSampleIdentifierPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/NewSampleIdentifierPredicate.java
index a15939a0a63..ee782ecb2b2 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/NewSampleIdentifierPredicate.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/predicate/NewSampleIdentifierPredicate.java
@@ -24,10 +24,14 @@ import ch.systemsx.cisd.openbis.generic.server.authorization.RoleWithIdentifier;
 import ch.systemsx.cisd.openbis.generic.server.authorization.project.IProjectAuthorization;
 import ch.systemsx.cisd.openbis.generic.server.authorization.project.ProjectAuthorizationBuilder;
 import ch.systemsx.cisd.openbis.generic.server.authorization.project.provider.project.ProjectProviderFromExperimentIdentifierString;
+import ch.systemsx.cisd.openbis.generic.server.authorization.project.provider.project.ProjectProviderFromProjectPE;
 import ch.systemsx.cisd.openbis.generic.server.authorization.project.provider.role.RolesProviderFromRolesWithIdentifier;
 import ch.systemsx.cisd.openbis.generic.server.authorization.project.provider.user.UserProviderFromPersonPE;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
 
@@ -70,18 +74,47 @@ public class NewSampleIdentifierPredicate extends AbstractPredicate<NewSample>
 
     private Status doEvaluationOfExperimentProject(PersonPE person, List<RoleWithIdentifier> allowedRoles, NewSample value)
     {
-        if (value.getExperimentIdentifier() != null)
+        SampleIdentifier identifier = SampleIdentifierFactory.parse(value.getIdentifier(), value.getDefaultSpaceIdentifier());
+
+        // This predicate is used in create, update and createOrUpdate methods, therefore we need to cover cases where a sample already exists or not.
+
+        SpacePE space = dataProvider.tryGetSpace(identifier.getSpaceLevel().getSpaceCode());
+
+        if (space != null)
         {
-            IProjectAuthorization<String> pa = new ProjectAuthorizationBuilder<String>()
-                    .withData(dataProvider)
-                    .withUser(new UserProviderFromPersonPE(person))
-                    .withRoles(new RolesProviderFromRolesWithIdentifier(allowedRoles))
-                    .withObjects(new ProjectProviderFromExperimentIdentifierString(value.getExperimentIdentifier()))
-                    .build();
-
-            if (pa.getObjectsWithoutAccess().isEmpty())
+            SamplePE sample = dataProvider.tryGetSampleBySpaceAndCode(space, identifier.getSampleCode());
+
+            if (sample == null)
             {
-                return Status.OK;
+                if (value.getExperimentIdentifier() != null)
+                {
+                    IProjectAuthorization<String> pa = new ProjectAuthorizationBuilder<String>()
+                            .withData(dataProvider)
+                            .withUser(new UserProviderFromPersonPE(person))
+                            .withRoles(new RolesProviderFromRolesWithIdentifier(allowedRoles))
+                            .withObjects(new ProjectProviderFromExperimentIdentifierString(value.getExperimentIdentifier()))
+                            .build();
+
+                    if (pa.getObjectsWithoutAccess().isEmpty())
+                    {
+                        return Status.OK;
+                    }
+                }
+            } else
+            {
+                ProjectPE project = sample.getExperiment() != null ? sample.getExperiment().getProject() : null;
+
+                IProjectAuthorization<ProjectPE> pa = new ProjectAuthorizationBuilder<ProjectPE>()
+                        .withData(dataProvider)
+                        .withUser(new UserProviderFromPersonPE(person))
+                        .withRoles(new RolesProviderFromRolesWithIdentifier(allowedRoles))
+                        .withObjects(new ProjectProviderFromProjectPE(project))
+                        .build();
+
+                if (pa.getObjectsWithoutAccess().isEmpty())
+                {
+                    return Status.OK;
+                }
             }
         }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/IRelationshipService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/IRelationshipService.java
index a036de8b01a..43faa76964b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/IRelationshipService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/IRelationshipService.java
@@ -131,7 +131,7 @@ public interface IRelationshipService
 
     @Transactional(propagation = Propagation.MANDATORY)
     @RolesAllowed(value =
-    { RoleWithHierarchy.SPACE_ETL_SERVER, RoleWithHierarchy.SPACE_POWER_USER })
+    { RoleWithHierarchy.SPACE_ETL_SERVER, RoleWithHierarchy.PROJECT_POWER_USER })
     @Capability("ASSIGN_DATASET_TO_SAMPLE")
     public void assignDataSetToSample(IAuthSession session,
             @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE dataSet,
@@ -172,28 +172,28 @@ public interface IRelationshipService
 
     @Transactional(propagation = Propagation.MANDATORY)
     @RolesAllowed(value =
-    { RoleWithHierarchy.SPACE_ETL_SERVER, RoleWithHierarchy.SPACE_POWER_USER })
+    { RoleWithHierarchy.SPACE_ETL_SERVER, RoleWithHierarchy.PROJECT_POWER_USER })
     @Capability("ADD_PARENT_TO_DATASET")
     public void addParentToDataSet(IAuthSession session,
             @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE data, @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE parent);
 
     @Transactional(propagation = Propagation.MANDATORY)
     @RolesAllowed(value =
-    { RoleWithHierarchy.SPACE_ETL_SERVER, RoleWithHierarchy.SPACE_POWER_USER })
+    { RoleWithHierarchy.SPACE_ETL_SERVER, RoleWithHierarchy.PROJECT_POWER_USER })
     @Capability("REMOVE_PARENT_FROM_DATASET")
     public void removeParentFromDataSet(IAuthSession session,
             @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE data, @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE parent);
 
     @Transactional(propagation = Propagation.MANDATORY)
     @RolesAllowed(value =
-    { RoleWithHierarchy.SPACE_ETL_SERVER, RoleWithHierarchy.SPACE_POWER_USER })
+    { RoleWithHierarchy.SPACE_ETL_SERVER, RoleWithHierarchy.PROJECT_POWER_USER })
     @Capability("ADD_CONTAINER_TO_DATASET")
     public void assignDataSetToContainer(IAuthSession session,
             @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE data,
             @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE container);
 
     @Transactional(propagation = Propagation.MANDATORY)
-    @RolesAllowed(value = { RoleWithHierarchy.SPACE_ETL_SERVER, RoleWithHierarchy.SPACE_POWER_USER })
+    @RolesAllowed(value = { RoleWithHierarchy.SPACE_ETL_SERVER, RoleWithHierarchy.PROJECT_POWER_USER })
     @Capability("REMOVE_CONTAINER_FROM_DATASET")
     public void removeDataSetFromContainer(IAuthSession session,
             @AuthorizationGuard(guardClass = DataPEPredicate.class) DataPE data,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
index 15124cdd817..0158b2679a3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java
@@ -371,6 +371,11 @@ abstract class AbstractBusinessObject implements IDAOFactory
         return daoFactory.getTransactionTimestamp();
     }
 
+    public IDAOFactory getDaoFactory()
+    {
+        return daoFactory;
+    }
+    
     @Override
     public final ISpaceDAO getSpaceDAO()
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/MetaprojectBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/MetaprojectBO.java
index 09a5e21c3cc..72237655c2c 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/MetaprojectBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/MetaprojectBO.java
@@ -26,7 +26,9 @@ import java.util.Map;
 import org.springframework.dao.DataAccessException;
 import org.springframework.orm.ObjectRetrievalFailureException;
 
+import ch.systemsx.cisd.common.exceptions.AuthorizationFailureException;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.generic.server.authorization.AuthorizationServiceUtils;
 import ch.systemsx.cisd.openbis.generic.server.business.IRelationshipService;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.util.DataSetTypeWithoutExperimentChecker;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.DynamicPropertyEvaluationOperation;
@@ -315,7 +317,6 @@ public class MetaprojectBO extends AbstractBusinessObject implements IMetaprojec
 
     private <T extends IObjectId> void addEntities(Collection<T> entityIds)
     {
-
         for (T entityId : entityIds)
         {
             IEntityWithMetaprojects entityPE = findById(entityId);
@@ -323,6 +324,13 @@ public class MetaprojectBO extends AbstractBusinessObject implements IMetaprojec
             {
                 throw new IllegalArgumentException("Entity for id: " + entityId + " doesn't exist.");
             }
+
+            boolean canAccess = canAccessEntity(entityPE);
+            if (false == canAccess)
+            {
+                throw new AuthorizationFailureException("Cannot access entity with id " + entityId);
+            }
+
             entitiesWithMetaproject.add(entityPE);
             addToChangedEntities(entityPE.getClass(), entityPE.getId());
         }
@@ -363,6 +371,28 @@ public class MetaprojectBO extends AbstractBusinessObject implements IMetaprojec
         }
     }
 
+    private boolean canAccessEntity(IEntityWithMetaprojects entity)
+    {
+        AuthorizationServiceUtils authorizationUtils = new AuthorizationServiceUtils(getDaoFactory(), findPerson());
+
+        if (entity instanceof MaterialPE)
+        {
+            return true;
+        } else if (entity instanceof ExperimentPE)
+        {
+            return authorizationUtils.canAccessExperiment((ExperimentPE) entity);
+        } else if (entity instanceof SamplePE)
+        {
+            return authorizationUtils.canAccessSample((SamplePE) entity);
+        } else if (entity instanceof DataPE)
+        {
+            return authorizationUtils.canAccessDataSet((DataPE) entity);
+        } else
+        {
+            throw new IllegalArgumentException("Unsupported entity kind " + entity.getClass());
+        }
+    }
+
     private Collection<Long> listEntityIds(EntityKind entityKind)
     {
         return getMetaprojectDAO().listMetaprojectEntityIds(metaproject.getId(), entityKind);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
index 3ae50a0d7af..a1187e88b84 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
@@ -292,7 +292,7 @@ public final class GenericServer extends AbstractServer<IGenericServerInternal>
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_OBSERVER)
     public AbstractExternalData getDataSetInfo(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) TechId datasetId)
     {
@@ -491,7 +491,7 @@ public final class GenericServer extends AbstractServer<IGenericServerInternal>
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_POWER_USER)
     @Capability("WRITE_DATASET")
     public void updateDataSets(final String sessionToken,
             @AuthorizationGuard(guardClass = NewDataSetsWithTypePredicate.class)
@@ -821,7 +821,7 @@ public final class GenericServer extends AbstractServer<IGenericServerInternal>
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_POWER_USER)
     @Capability("WRITE_DATASET")
     public DataSetUpdateResult updateDataSet(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetUpdatesPredicate.class) DataSetUpdatesDTO updates)
@@ -1014,7 +1014,7 @@ public final class GenericServer extends AbstractServer<IGenericServerInternal>
     }
 
     @Override
-    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     @Capability("WRITE_SAMPLE")
     public void updateTemporaryCodes(String sessionToken, Map<String, List<String>> sampleTypeCodeToTemporaryIdentifiers)
     {
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/CreateDataSetTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/CreateDataSetTest.java
index 0bc7633ffa5..55db3db42a5 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/CreateDataSetTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/CreateDataSetTest.java
@@ -72,6 +72,7 @@ import ch.systemsx.cisd.common.action.IDelegatedAction;
 import ch.systemsx.cisd.common.test.AssertionUtil;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewETPTAssignment;
+import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 
 /**
  * @author pkupczyk
@@ -85,7 +86,7 @@ public class CreateDataSetTest extends AbstractDataSetTest
         String code = UUID.randomUUID().toString();
         LinkedDataCreation linkedData = new LinkedDataCreation();
         linkedData.setExternalDmsId(new ExternalDmsPermId("DMS_1"));
-        linkedData.setExternalCode("test-"+System.currentTimeMillis());
+        linkedData.setExternalCode("test-" + System.currentTimeMillis());
         DataSetCreation creation = new DataSetCreation();
         creation.setCode(code);
         creation.setTypeId(new EntityTypePermId("LINK_TYPE"));
@@ -99,7 +100,7 @@ public class CreateDataSetTest extends AbstractDataSetTest
         assertEquals(dataSets.get(0).getPermId(), code.toUpperCase());
         assertEquals(dataSets.size(), 1);
     }
-    
+
     @Test
     public void testCreateContainerDataSetWithSpaceUser()
     {
@@ -111,75 +112,75 @@ public class CreateDataSetTest extends AbstractDataSetTest
         creation.setExperimentId(new ExperimentIdentifier("/TEST-SPACE/NOE/EXP-TEST-2"));
         creation.setDataStoreId(new DataStorePermId("STANDARD"));
         creation.setCreationId(new CreationId(code));
-        
+
         List<DataSetPermId> dataSets = v3api.createDataSets(sessionToken, Collections.singletonList(creation));
-        
+
         assertEquals(dataSets.get(0).getPermId(), code.toUpperCase());
         assertEquals(dataSets.size(), 1);
     }
-    
+
     @Test
     public void testCreateDSWithAdminUserInBehalfOfASpaceObserver()
     {
         final DataSetPermId permId = new DataSetPermId("NO_SHALL_CREATE");
-        
+
         assertUserFailureException(new IDelegatedAction()
-        {
-            @Override
-            public void execute()
             {
-                String sessionToken = v3api.loginAs(TEST_USER, PASSWORD, TEST_OBSERVER_CISD);
-                
-                PhysicalDataCreation physicalCreation = new PhysicalDataCreation();
-                physicalCreation.setLocation("test/location/" + permId.getPermId());
-                physicalCreation.setFileFormatTypeId(new FileFormatTypePermId("TIFF"));
-                physicalCreation.setLocatorTypeId(new RelativeLocationLocatorTypePermId());
-                physicalCreation.setStorageFormatId(new ProprietaryStorageFormatPermId());
-                
-                DataSetCreation creation = new DataSetCreation();
-                creation.setCode(permId.getPermId());
-                creation.setTypeId(new EntityTypePermId("UNKNOWN"));
-                creation.setDataStoreId(new DataStorePermId("STANDARD"));
-                creation.setExperimentId(new ExperimentIdentifier("/CISD/NEMO/EXP1"));
-                creation.setPhysicalData(physicalCreation);
-                creation.setCreationId(new CreationId(permId.getPermId()));
-                
-                v3api.createDataSets(sessionToken, Collections.singletonList(creation));
-            }
-        }, "Access denied to object with DataSetPermId = [NO_SHALL_CREATE]");
-    }
-    
+                @Override
+                public void execute()
+                {
+                    String sessionToken = v3api.loginAs(TEST_USER, PASSWORD, TEST_OBSERVER_CISD);
+
+                    PhysicalDataCreation physicalCreation = new PhysicalDataCreation();
+                    physicalCreation.setLocation("test/location/" + permId.getPermId());
+                    physicalCreation.setFileFormatTypeId(new FileFormatTypePermId("TIFF"));
+                    physicalCreation.setLocatorTypeId(new RelativeLocationLocatorTypePermId());
+                    physicalCreation.setStorageFormatId(new ProprietaryStorageFormatPermId());
+
+                    DataSetCreation creation = new DataSetCreation();
+                    creation.setCode(permId.getPermId());
+                    creation.setTypeId(new EntityTypePermId("UNKNOWN"));
+                    creation.setDataStoreId(new DataStorePermId("STANDARD"));
+                    creation.setExperimentId(new ExperimentIdentifier("/CISD/NEMO/EXP1"));
+                    creation.setPhysicalData(physicalCreation);
+                    creation.setCreationId(new CreationId(permId.getPermId()));
+
+                    v3api.createDataSets(sessionToken, Collections.singletonList(creation));
+                }
+            }, "Access denied to object with DataSetPermId = [NO_SHALL_CREATE]");
+    }
+
     @Test
     public void testCreateDSForSampleWithAdminUserInBehalfOfASpaceObserver()
     {
         final DataSetPermId permId = new DataSetPermId("NO_SHALL_CREATE");
-        
+
         assertUserFailureException(new IDelegatedAction()
-        {
-            @Override
-            public void execute()
             {
-                String sessionToken = v3api.loginAs(TEST_USER, PASSWORD, TEST_OBSERVER_CISD);
-                
-                PhysicalDataCreation physicalCreation = new PhysicalDataCreation();
-                physicalCreation.setLocation("test/location/" + permId.getPermId());
-                physicalCreation.setFileFormatTypeId(new FileFormatTypePermId("TIFF"));
-                physicalCreation.setLocatorTypeId(new RelativeLocationLocatorTypePermId());
-                physicalCreation.setStorageFormatId(new ProprietaryStorageFormatPermId());
-                
-                DataSetCreation creation = new DataSetCreation();
-                creation.setCode(permId.getPermId());
-                creation.setTypeId(new EntityTypePermId("UNKNOWN"));
-                creation.setSampleId(new SampleIdentifier("/CISD/C1"));
-                creation.setDataStoreId(new DataStorePermId("STANDARD"));
-                creation.setPhysicalData(physicalCreation);
-                creation.setCreationId(new CreationId(permId.getPermId()));
-                
-                v3api.createDataSets(sessionToken, Collections.singletonList(creation));
-            }
-        }, "Access denied to object with DataSetPermId = [NO_SHALL_CREATE]");
-    }
-    
+                @Override
+                public void execute()
+                {
+                    String sessionToken = v3api.loginAs(TEST_USER, PASSWORD, TEST_OBSERVER_CISD);
+
+                    PhysicalDataCreation physicalCreation = new PhysicalDataCreation();
+                    physicalCreation.setLocation("test/location/" + permId.getPermId());
+                    physicalCreation.setFileFormatTypeId(new FileFormatTypePermId("TIFF"));
+                    physicalCreation.setLocatorTypeId(new RelativeLocationLocatorTypePermId());
+                    physicalCreation.setStorageFormatId(new ProprietaryStorageFormatPermId());
+
+                    DataSetCreation creation = new DataSetCreation();
+                    creation.setCode(permId.getPermId());
+                    creation.setTypeId(new EntityTypePermId("UNKNOWN"));
+                    creation.setSampleId(new SampleIdentifier("/CISD/C1"));
+                    creation.setDataStoreId(new DataStorePermId("STANDARD"));
+                    creation.setPhysicalData(physicalCreation);
+                    creation.setCreationId(new CreationId(permId.getPermId()));
+
+                    v3api.createDataSets(sessionToken, Collections.singletonList(creation));
+                }
+            }, "Access denied to object with DataSetPermId = [NO_SHALL_CREATE]");
+    }
+
     @Test
     public void testArchiveWithAdminUserInAnotherSpace()
     {
@@ -1790,6 +1791,31 @@ public class CreateDataSetTest extends AbstractDataSetTest
             }, "External data management system id cannot be null for a link data set.");
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testCreateWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String sessionToken = v3api.loginAs(TEST_USER, PASSWORD, user.getUserId());
+
+        DataSetCreation creation = physicalDataSetCreation();
+        creation.setExperimentId(new ExperimentIdentifier("/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST"));
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<DataSetPermId> permIds = v3api.createDataSets(sessionToken, Collections.singletonList(creation));
+            assertEquals(permIds.size(), 1);
+        } else
+        {
+            assertUnauthorizedObjectAccessException(new IDelegatedAction()
+                {
+                    @Override
+                    public void execute()
+                    {
+                        v3api.createDataSets(sessionToken, Collections.singletonList(creation));
+                    }
+                }, creation.getExperimentId());
+        }
+    }
+
     private DataSetCreation physicalDataSetCreation()
     {
         String code = UUID.randomUUID().toString();
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DeleteDataSetTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DeleteDataSetTest.java
index 548f9d15c59..52ea9cbb31a 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DeleteDataSetTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DeleteDataSetTest.java
@@ -17,14 +17,18 @@
 package ch.ethz.sis.openbis.systemtest.asapi.v3;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 
 import org.testng.annotations.Test;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.delete.DataSetDeletionOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.deletion.id.IDeletionId;
 import ch.systemsx.cisd.common.action.IDelegatedAction;
+import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
+
 import junit.framework.Assert;
 
 /**
@@ -130,13 +134,34 @@ public class DeleteDataSetTest extends AbstractDeletionTest
                 {
                     String sessionToken = v3api.login(TEST_ROLE_V3, PASSWORD);
 
-                    DataSetDeletionOptions options = new DataSetDeletionOptions();
-                    options.setReason("It is just a test");
-
-                    v3api.deleteDataSets(sessionToken, Collections.singletonList(permId), options);
+                    v3api.deleteDataSets(sessionToken, Collections.singletonList(permId), getOptions());
                 }
             }, permId);
     }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testDeleteWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String sessionToken = v3api.login(user.getUserId(), PASSWORD);
+
+        IDataSetId dataSetId = new DataSetPermId("20120628092259000-41");
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            v3api.deleteDataSets(sessionToken, Arrays.asList(dataSetId), getOptions());
+        } else
+        {
+            assertUnauthorizedObjectAccessException(new IDelegatedAction()
+                {
+                    @Override
+                    public void execute()
+                    {
+                        v3api.deleteDataSets(sessionToken, Arrays.asList(dataSetId), getOptions());
+                    }
+                }, dataSetId);
+        }
+    }
+
     // waiting for better times
     // @Test
     // public void testDeleteContainerInDifferentExperiment()
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetDataSetTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetDataSetTest.java
index 4f62f8412e0..bc09715ef7b 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetDataSetTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetDataSetTest.java
@@ -58,6 +58,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SampleIdentifier;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SamplePermId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.Tag;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.fetchoptions.TagFetchOptions;
+import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 
 /**
  * @author pkupczyk
@@ -1012,6 +1013,30 @@ public class GetDataSetTest extends AbstractDataSetTest
         assertEquals(entry.getRelatedObjectId(), new DataSetPermId("COMPONENT_2A"));
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testGetWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        List<IDataSetId> ids = Arrays.asList(new DataSetPermId("20120619092259000-22"),
+                new DataSetPermId("20081105092159188-3"));
+
+        String sessionToken = v3api.login(user.getUserId(), PASSWORD);
+        Map<IDataSetId, DataSet> result = v3api.getDataSets(sessionToken, ids, new DataSetFetchOptions());
+
+        if (user.isInstanceUser())
+        {
+            assertEquals(result.size(), 2);
+        } else if (user.isTestSpaceUser() || (user.isTestProjectUser() && user.hasPAEnabled()))
+        {
+            assertEquals(result.size(), 1);
+            assertEquals(result.values().iterator().next().getCode(), "20120619092259000-22");
+        } else
+        {
+            assertEquals(result.size(), 0);
+        }
+
+        v3api.logout(sessionToken);
+    }
+
     private List<HistoryEntry> testGetWithHistory(DataSetUpdate... updates)
     {
         String sessionToken = v3api.login(TEST_USER, PASSWORD);
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SearchDataSetTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SearchDataSetTest.java
index 1a294628498..37445288543 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SearchDataSetTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SearchDataSetTest.java
@@ -32,6 +32,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.search.DataSetSearchCrit
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.search.SampleSearchCriteria;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.id.TagPermId;
+import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 
 /**
  * @author pkupczyk
@@ -719,6 +720,32 @@ public class SearchDataSetTest extends AbstractDataSetTest
         v3api.logout(sessionToken);
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testSearchWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        DataSetSearchCriteria criteria = new DataSetSearchCriteria();
+        criteria.withOrOperator();
+        criteria.withId().thatEquals(new DataSetPermId("20120619092259000-22"));
+        criteria.withId().thatEquals(new DataSetPermId("20081105092159188-3"));
+
+        String sessionToken = v3api.login(user.getUserId(), PASSWORD);
+        SearchResult<DataSet> result = v3api.searchDataSets(sessionToken, criteria, new DataSetFetchOptions());
+
+        if (user.isInstanceUser())
+        {
+            assertEquals(result.getObjects().size(), 2);
+        } else if (user.isTestSpaceUser() || (user.isTestProjectUser() && user.hasPAEnabled()))
+        {
+            assertEquals(result.getObjects().size(), 1);
+            assertEquals(result.getObjects().get(0).getCode(), "20120619092259000-22");
+        } else
+        {
+            assertEquals(result.getObjects().size(), 0);
+        }
+
+        v3api.logout(sessionToken);
+    }
+
     private void testSearch(String user, DataSetSearchCriteria criteria, String... expectedIdentifiers)
     {
         List<DataSet> dataSets = searchDataSets(user, criteria, new DataSetFetchOptions());
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/UpdateDataSetTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/UpdateDataSetTest.java
index d742a26f9c5..89e24117e58 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/UpdateDataSetTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/UpdateDataSetTest.java
@@ -44,6 +44,7 @@ import ch.ethz.sis.openbis.systemtest.asapi.v3.index.ReindexingState;
 import ch.systemsx.cisd.common.action.IDelegatedAction;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.test.AssertionUtil;
+import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 
 /**
  * @author pkupczyk
@@ -715,6 +716,31 @@ public class UpdateDataSetTest extends AbstractSampleTest
         AssertionUtil.assertCollectionContainsOnly(tagCodes(result.get(dataSet).getTags()), newTag1.getCode(), newTag2.getCode());
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testUpdateWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String sessionToken = v3api.login(user.getUserId(), PASSWORD);
+
+        DataSetUpdate update = new DataSetUpdate();
+        update.setDataSetId(new DataSetPermId("20120619092259000-22"));
+        update.setProperty("COMMENT", "updated comment");
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            v3api.updateDataSets(sessionToken, Arrays.asList(update));
+        } else
+        {
+            assertUnauthorizedObjectAccessException(new IDelegatedAction()
+                {
+                    @Override
+                    public void execute()
+                    {
+                        v3api.updateDataSets(sessionToken, Arrays.asList(update));
+                    }
+                }, update.getDataSetId());
+        }
+    }
+
     private Collection<String> dataSetCodes(Collection<? extends DataSet> list)
     {
         LinkedList<String> result = new LinkedList<String>();
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServerTest.java
index 66c92af4d62..65c2d460ae3 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ServiceForDataStoreServerTest.java
@@ -34,11 +34,13 @@ 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.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetBatchUpdateDetails;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentFetchOptions;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IDatasetLocationNode;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LocatorType;
@@ -53,6 +55,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
 import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationResult;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetBatchUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ListSamplesByPropertyCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData;
@@ -522,6 +525,30 @@ public class ServiceForDataStoreServerTest extends SystemTestCase
         }
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testListDataSetsByCodeWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = etlService.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<AbstractExternalData> dataSets = etlService.listDataSetsByCode(session.getSessionToken(), Arrays.asList(dataSetCode));
+            assertEntities("[20120628092259000-41]", dataSets);
+        } else
+        {
+            try
+            {
+                etlService.listDataSetsByCode(session.getSessionToken(), Arrays.asList(dataSetCode));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
     public void testTryGetPropertiesOfTopSampleWithProjectAuthorization(ProjectAuthorizationUser user)
     {
@@ -680,7 +707,7 @@ public class ServiceForDataStoreServerTest extends SystemTestCase
     {
         SessionContextDTO session = etlService.tryAuthenticate(user.getUserId(), PASSWORD);
 
-        NewExternalData newData = createNewExternalData("TEST-DATASET");
+        NewExternalData newData = createNewDataSet("TEST-DATASET");
 
         if (user.isInstanceUser() || (user.isETLServerUser() && user.isTestSpaceUser()))
         {
@@ -707,7 +734,7 @@ public class ServiceForDataStoreServerTest extends SystemTestCase
         SessionContextDTO session = etlService.tryAuthenticate(user.getUserId(), PASSWORD);
 
         NewSample newSample = createNewSample("/TEST-SPACE/TEST-SAMPLE", "/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST");
-        NewExternalData newExternalData = createNewExternalData("TEST-DATASET");
+        NewExternalData newExternalData = createNewDataSet("TEST-DATASET");
 
         if (user.isInstanceUser() || (user.isETLServerUser() && user.isTestSpaceUser()))
         {
@@ -734,7 +761,7 @@ public class ServiceForDataStoreServerTest extends SystemTestCase
         SessionContextDTO session = etlService.tryAuthenticate(user.getUserId(), PASSWORD);
 
         SampleUpdatesDTO sampleUpdates = createSampleUpdates(1055, "/TEST-SPACE/EV-TEST", "COMMENT", "updated comment");
-        NewExternalData newExternalData = createNewExternalData("TEST-DATASET");
+        NewExternalData newExternalData = createNewDataSet("TEST-DATASET");
 
         if (user.isInstanceUser() || (user.isETLServerUser() && user.isTestSpaceUser()))
         {
@@ -1077,6 +1104,211 @@ public class ServiceForDataStoreServerTest extends SystemTestCase
         }
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testPerformEntityOperationsWithNewDataSetWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO adminSession = etlService.tryAuthenticate(TEST_USER, PASSWORD);
+
+        NewExternalData newDataSet = createNewDataSet("PA_PERFORM_ENTITY_OPERATIONS_DATA_SET");
+        newDataSet.setExperimentIdentifierOrNull(new ExperimentIdentifier("TEST-SPACE", "TEST-PROJECT", "EXP-SPACE-TEST"));
+
+        AtomicEntityOperationDetails operation =
+                new AtomicEntityOperationDetails(null, user.getUserId(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(),
+                        Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(),
+                        Collections.emptyMap(), Collections.emptyList(), Arrays.asList(newDataSet), Collections.emptyList(), Collections.emptyList(),
+                        Collections.emptyList(), Collections.emptyList());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            AtomicEntityOperationResult result = etlService.performEntityOperations(adminSession.getSessionToken(), operation);
+            assertEquals(result.getDataSetsCreatedCount(), 1);
+        } else
+        {
+            try
+            {
+                etlService.performEntityOperations(adminSession.getSessionToken(), operation);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testPerformEntityOperationsWithDataSetUpdateWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO adminSession = etlService.tryAuthenticate(TEST_USER, PASSWORD);
+
+        DataSetBatchUpdatesDTO dataSetUpdate = createDataSetUpdates(22, "20120619092259000-22", "COMMENT", "updated comment");
+
+        AtomicEntityOperationDetails operation =
+                new AtomicEntityOperationDetails(null, user.getUserId(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(),
+                        Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(),
+                        Collections.emptyMap(), Collections.emptyList(), Collections.emptyList(), Arrays.asList(dataSetUpdate),
+                        Collections.emptyList(),
+                        Collections.emptyList(), Collections.emptyList());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            AtomicEntityOperationResult result = etlService.performEntityOperations(adminSession.getSessionToken(), operation);
+            assertEquals(result.getDataSetsUpdatedCount(), 1);
+        } else
+        {
+            try
+            {
+                etlService.performEntityOperations(adminSession.getSessionToken(), operation);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testTryGetDataSetLocationWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = etlService.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120619092259000-22";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            IDatasetLocationNode location = etlService.tryGetDataSetLocation(session.getSessionToken(), dataSetCode);
+            assertEquals(location.getLocation().getDataSetCode(), dataSetCode);
+        } else
+        {
+            try
+            {
+                etlService.tryGetDataSetLocation(session.getSessionToken(), dataSetCode);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testTryGetLocalDataSetWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = etlService.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120619092259000-22";
+        String dataStore = "STANDARD";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            AbstractExternalData dataSet = etlService.tryGetLocalDataSet(session.getSessionToken(), dataSetCode, dataStore);
+            assertEquals(dataSet.getCode(), dataSetCode);
+        } else
+        {
+            try
+            {
+                etlService.tryGetLocalDataSet(session.getSessionToken(), dataSetCode, dataStore);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testTryGetDataSetWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = etlService.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120619092259000-22";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            AbstractExternalData dataSet = etlService.tryGetDataSet(session.getSessionToken(), dataSetCode);
+            assertEquals(dataSet.getCode(), dataSetCode);
+        } else
+        {
+            try
+            {
+                etlService.tryGetDataSet(session.getSessionToken(), dataSetCode);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testTryGetThinDataSetWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = etlService.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120619092259000-22";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            AbstractExternalData dataSet = etlService.tryGetThinDataSet(session.getSessionToken(), dataSetCode);
+            assertEquals(dataSet.getCode(), dataSetCode);
+        } else
+        {
+            try
+            {
+                etlService.tryGetThinDataSet(session.getSessionToken(), dataSetCode);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testCheckDataSetAccessWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = etlService.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120619092259000-22";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            etlService.checkDataSetAccess(session.getSessionToken(), dataSetCode);
+        } else
+        {
+            try
+            {
+                etlService.checkDataSetAccess(session.getSessionToken(), dataSetCode);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER_WITH_ETL)
+    public void testCheckDataSetCollectionAccessWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = etlService.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120619092259000-22";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            etlService.checkDataSetCollectionAccess(session.getSessionToken(), Arrays.asList(dataSetCode));
+        } else
+        {
+            try
+            {
+                etlService.checkDataSetCollectionAccess(session.getSessionToken(), Arrays.asList(dataSetCode));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
     private NewExperiment createNewExperiment(String experimentIdentifier)
     {
         NewExperiment newExperiment = new NewExperiment();
@@ -1107,7 +1339,7 @@ public class ServiceForDataStoreServerTest extends SystemTestCase
         return updates;
     }
 
-    private NewExternalData createNewExternalData(String dataSetCode)
+    private NewExternalData createNewDataSet(String dataSetCode)
     {
         DataSetType type = new DataSetType();
         type.setCode("UNKNOWN");
@@ -1123,6 +1355,16 @@ public class ServiceForDataStoreServerTest extends SystemTestCase
         return newData;
     }
 
+    private DataSetBatchUpdatesDTO createDataSetUpdates(long dataSetId, String dataSetCode, String propertyCode, String propertyValue)
+    {
+        DataSetBatchUpdatesDTO updates = new DataSetBatchUpdatesDTO();
+        updates.setDatasetId(new TechId(dataSetId));
+        updates.setDatasetCode(dataSetCode);
+        updates.setProperties(Arrays.asList(createEntityProperty(propertyCode, propertyValue)));
+        updates.setDetails(new DataSetBatchUpdateDetails());
+        return updates;
+    }
+
     private IEntityProperty createEntityProperty(String propertyCode, String propertyValue)
     {
         IEntityProperty property = new EntityProperty();
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerDatabaseTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerDatabaseTest.java
index a4f389480e3..ba605f30ba9 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerDatabaseTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerDatabaseTest.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.plugin.generic.server;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
 
 import java.sql.SQLException;
 import java.util.ArrayList;
@@ -36,9 +37,11 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.AbstractDAOTest;
 import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AttachmentWithContent;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetBatchUpdateDetails;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetUpdateResult;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentBatchUpdateDetails;
@@ -61,6 +64,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.UpdatedBasicExperiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.UpdatedDataSet;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.UpdatedExperimentsWithType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUpdatesDTO;
 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.SamplePE;
@@ -245,11 +249,11 @@ public class GenericServerDatabaseTest extends AbstractDAOTest
     public void testListProjectAttachmentWithProjectAuthorization(ProjectAuthorizationUser user)
     {
         SessionContextDTO sessionDTO = server.tryAuthenticate(user.getUserId(), PASSWORD);
-        
+
         TechId projectId = new TechId(5); // /TEST_SPACE/TEST_PROJECT
         String fileName = "testProject.txt";
         Integer version = 1;
-        
+
         if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
         {
             AttachmentWithContent attachment = server.getProjectFileAttachment(sessionDTO.getSessionToken(), projectId, fileName, version);
@@ -267,7 +271,7 @@ public class GenericServerDatabaseTest extends AbstractDAOTest
             }
         }
     }
-    
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
     public void testRegisterExperimentWithProjectAuthorization(ProjectAuthorizationUser user)
     {
@@ -606,6 +610,105 @@ public class GenericServerDatabaseTest extends AbstractDAOTest
         }
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testGetDataSetInfoWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO sessionDTO = server.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        TechId dataSetId = new TechId(41L); // 20120628092259000-41
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            AbstractExternalData dataSet = server.getDataSetInfo(sessionDTO.getSessionToken(), dataSetId);
+            assertEquals(dataSet.getCode(), "20120628092259000-41");
+        } else
+        {
+            try
+            {
+                server.getDataSetInfo(sessionDTO.getSessionToken(), dataSetId);
+                Assert.fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testUpdateDataSetWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO sessionDTO = server.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        IEntityProperty property = new EntityProperty();
+        property.setValue("test comment");
+        PropertyType propertyType = new PropertyType();
+        propertyType.setCode("COMMENT");
+        property.setPropertyType(propertyType);
+
+        DataSetUpdatesDTO updates = new DataSetUpdatesDTO();
+        updates.setDatasetId(new TechId(22L)); // 20120619092259000-22
+        updates.setProperties(Arrays.asList(new IEntityProperty[] { property }));
+        updates.setFileFormatTypeCode("XML");
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            DataSetUpdateResult result = server.updateDataSet(sessionDTO.getSessionToken(), updates);
+            assertNotNull(result);
+
+            AbstractExternalData dataSet = server.getDataSetInfo(sessionDTO.getSessionToken(), updates.getDatasetId());
+            assertEquals(dataSet.getProperties().get(0).getValue(), property.getValue());
+        } else
+        {
+            try
+            {
+                server.updateDataSet(sessionDTO.getSessionToken(), updates);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testUpdateDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO sessionDTO = server.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        IEntityProperty property = new EntityProperty();
+        property.setValue("test comment");
+        PropertyType propertyType = new PropertyType();
+        propertyType.setCode("COMMENT");
+        property.setPropertyType(propertyType);
+
+        NewDataSet newDataSet = new NewDataSet();
+        newDataSet.setCode("20120619092259000-22");
+        newDataSet.setProperties(new IEntityProperty[] { property });
+
+        TechId dataSetId = new TechId(22L);
+        DataSetType dataSetType = new DataSetType("UNKNOWN");
+
+        NewDataSetsWithTypes newDataSets = new NewDataSetsWithTypes(dataSetType, Arrays.asList(newDataSet));
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            server.updateDataSets(sessionDTO.getSessionToken(), newDataSets);
+
+            AbstractExternalData dataSet = server.getDataSetInfo(sessionDTO.getSessionToken(), dataSetId);
+            assertEquals(dataSet.getProperties().get(0).getValue(), property.getValue());
+        } else
+        {
+            try
+            {
+                server.updateDataSets(sessionDTO.getSessionToken(), newDataSets);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
     private void update(DataPE data, NewDataSet newDataset, DataSetBatchUpdateDetails updateDetails)
     {
         List<NewDataSet> newDatasets = new ArrayList<NewDataSet>();
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/CommonServerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/CommonServerTest.java
index f5057de9810..d7a54ab1fbd 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/CommonServerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/CommonServerTest.java
@@ -44,6 +44,7 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
+import ch.systemsx.cisd.openbis.generic.shared.basic.BasicEntityInformationHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData;
@@ -51,7 +52,11 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AttachmentWithContent;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AuthorizationGroup;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ContainerDataSet;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelatedEntities;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetRelationshipRole;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetUpdateResult;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatastoreServiceDescription;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DeletionType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriterion;
@@ -82,15 +87,19 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleParentWithDerived
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleUpdateResult;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SearchCriteriaConnection;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.displaysettings.IDisplaySettingsUpdate;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.id.dataset.DataSetCodeId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.id.experiment.ExperimentIdentifierId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.id.metaproject.MetaprojectIdentifierId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.id.sample.SampleIdentifierId;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUpdatesDTO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 
 import junit.framework.Assert;
@@ -955,6 +964,31 @@ public class CommonServerTest extends SystemTestCase
         }
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListExperimentsByExperimentTypeAndSpaceIdentifierWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        ExperimentType experimentType = new ExperimentType();
+        experimentType.setCode("SIRNA_HCS");
+
+        List<Experiment> experiments = commonServer.listExperiments(session.getSessionToken(), experimentType, new SpaceIdentifier("TEST-SPACE"));
+
+        if (user.isInstanceUser() || user.isTestSpaceUser())
+        {
+            assertEquals(experiments.size(), 3);
+            assertEntities("[/TEST-SPACE/NOE/EXP-TEST-2, /TEST-SPACE/NOE/EXPERIMENT-TO-DELETE, /TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST]",
+                    experiments);
+        } else if (user.isTestProjectUser() && user.hasPAEnabled())
+        {
+            assertEquals(experiments.size(), 1);
+            assertEntities("[/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST]", experiments);
+        } else
+        {
+            assertEquals(experiments.size(), 0);
+        }
+    }
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
     public void testListExperimentsByExperimentTypeAndProjectIdentifierWithProjectAuthorization(ProjectAuthorizationUser user)
     {
@@ -1015,9 +1049,9 @@ public class CommonServerTest extends SystemTestCase
     public void testListExperimentsByExperimentIdentifiersWithProjectAuthorization(ProjectAuthorizationUser user)
     {
         SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
-        
+
         ExperimentIdentifier experimentIdentifier = new ExperimentIdentifier("TEST-SPACE", "TEST-PROJECT", "EXP-SPACE-TEST");
-        
+
         if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
         {
             List<Experiment> experiments = commonServer.listExperiments(session.getSessionToken(), Arrays.asList(experimentIdentifier));
@@ -1035,7 +1069,7 @@ public class CommonServerTest extends SystemTestCase
             }
         }
     }
-    
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
     public void testListExperimentsHavingSamplesWithProjectAuthorization(ProjectAuthorizationUser user)
     {
@@ -1154,6 +1188,35 @@ public class CommonServerTest extends SystemTestCase
         }
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListMetaprojectExternalDataWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        Metaproject metaproject = new Metaproject();
+        metaproject.setName("TEST_LIST_METAPROJECT_DATASETS");
+        metaproject = commonServer.registerMetaproject(session.getSessionToken(), metaproject);
+
+        MetaprojectAssignmentsIds assignments = new MetaprojectAssignmentsIds();
+        assignments.addDataSet(new DataSetCodeId("20120628092259000-41"));
+
+        commonServer.addToMetaproject(session.getSessionToken(), new MetaprojectIdentifierId(metaproject.getIdentifier()), assignments);
+
+        List<AbstractExternalData> dataSets =
+                commonServer.listMetaprojectExternalData(session.getSessionToken(), new MetaprojectIdentifierId(metaproject.getIdentifier()));
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            assertEquals(dataSets.size(), 1);
+            assertEquals(dataSets.get(0).isStub(), false);
+            assertEquals(dataSets.get(0).getCode(), "20120628092259000-41");
+        } else
+        {
+            assertEquals(dataSets.size(), 1);
+            assertEquals(dataSets.get(0).isStub(), true);
+        }
+    }
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
     public void testSearchForSamplesWithProjectAuthorization(ProjectAuthorizationUser user)
     {
@@ -1200,19 +1263,71 @@ public class CommonServerTest extends SystemTestCase
         criteria.setCriteria(Arrays.asList(criterion));
         criteria.setConnection(SearchCriteriaConnection.MATCH_ANY);
 
+        List<Experiment> experiments =
+                commonServer.searchForExperiments(session.getSessionToken(), criteria);
+
         if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
         {
-            List<Experiment> experiments =
-                    commonServer.searchForExperiments(session.getSessionToken(), criteria);
             assertEquals(experiments.size(), 1);
             assertEquals(experiments.get(0).getIdentifier(), "/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST");
         } else
         {
-            List<Experiment> experiments = commonServer.searchForExperiments(session.getSessionToken(), criteria);
             assertEquals(experiments.size(), 0);
         }
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testSearchForDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        DetailedSearchCriterion criterion = new DetailedSearchCriterion();
+        criterion.setField(DetailedSearchField.createAttributeField(ExperimentAttributeSearchFieldKind.CODE));
+        criterion.setValue("20120628092259000-41");
+
+        DetailedSearchCriteria criteria = new DetailedSearchCriteria();
+        criteria.setCriteria(Arrays.asList(criterion));
+        criteria.setConnection(SearchCriteriaConnection.MATCH_ANY);
+
+        List<AbstractExternalData> dataSets =
+                commonServer.searchForDataSets(session.getSessionToken(), criteria);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            assertEquals(dataSets.size(), 1);
+            assertEquals(dataSets.get(0).getCode(), "20120628092259000-41");
+        } else
+        {
+            assertEquals(dataSets.size(), 0);
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testSearchForDataSetsOnBehalfOfUserWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(TEST_USER, PASSWORD);
+
+        DetailedSearchCriterion criterion = new DetailedSearchCriterion();
+        criterion.setField(DetailedSearchField.createAttributeField(ExperimentAttributeSearchFieldKind.CODE));
+        criterion.setValue("20120628092259000-41");
+
+        DetailedSearchCriteria criteria = new DetailedSearchCriteria();
+        criteria.setCriteria(Arrays.asList(criterion));
+        criteria.setConnection(SearchCriteriaConnection.MATCH_ANY);
+
+        List<AbstractExternalData> dataSets =
+                commonServer.searchForDataSetsOnBehalfOfUser(session.getSessionToken(), criteria, user.getUserId());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            assertEquals(dataSets.size(), 1);
+            assertEquals(dataSets.get(0).getCode(), "20120628092259000-41");
+        } else
+        {
+            assertEquals(dataSets.size(), 0);
+        }
+    }
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
     public void testUpdateExperimentAttachmentsWithProjectAuthorization(ProjectAuthorizationUser user)
     {
@@ -1447,6 +1562,42 @@ public class CommonServerTest extends SystemTestCase
         }
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testUpdateDataSetWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        IEntityProperty property = new EntityProperty();
+        property.setValue("test comment");
+        PropertyType propertyType = new PropertyType();
+        propertyType.setCode("COMMENT");
+        property.setPropertyType(propertyType);
+
+        DataSetUpdatesDTO updates = new DataSetUpdatesDTO();
+        updates.setDatasetId(new TechId(22L)); // 20120619092259000-22
+        updates.setProperties(Arrays.asList(new IEntityProperty[] { property }));
+        updates.setFileFormatTypeCode("XML");
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            DataSetUpdateResult result = commonServer.updateDataSet(session.getSessionToken(), updates);
+            assertNotNull(result);
+
+            AbstractExternalData dataSet = commonServer.getDataSetInfo(session.getSessionToken(), updates.getDatasetId());
+            assertEquals(dataSet.getProperties().get(0).getValue(), property.getValue());
+        } else
+        {
+            try
+            {
+                commonServer.updateDataSet(session.getSessionToken(), updates);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
     public void testUpdateExperimentPropertiesWithProjectAuthorization(ProjectAuthorizationUser user)
     {
@@ -1510,6 +1661,442 @@ public class CommonServerTest extends SystemTestCase
         }
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testUpdateDataSetPropertiesWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        PropertyUpdates property = new PropertyUpdates();
+        property.setPropertyCode("COMMENT");
+        property.setValue("test comment");
+
+        TechId dataSetId = new TechId(22L); // 20120619092259000-22
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            commonServer.updateDataSetProperties(session.getSessionToken(), dataSetId, Arrays.asList(property));
+
+            AbstractExternalData dataSet = commonServer.getDataSetInfo(session.getSessionToken(), dataSetId);
+            assertEquals(dataSet.getProperties().get(0).getValue(), property.getValue());
+        } else
+        {
+            try
+            {
+                commonServer.updateDataSetProperties(session.getSessionToken(), dataSetId, Arrays.asList(property));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListSampleExternalDataWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        TechId sampleId = new TechId(1054L); // /TEST-SPACE/FV-TEST
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<AbstractExternalData> dataSets = commonServer.listSampleExternalData(session.getSessionToken(), sampleId, true);
+            assertEntities("[20120628092259000-41]", dataSets);
+        } else
+        {
+            try
+            {
+                commonServer.listSampleExternalData(session.getSessionToken(), sampleId, true);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListExperimentExternalDataWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        TechId experimentId = new TechId(23L); // /TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<AbstractExternalData> dataSets = commonServer.listExperimentExternalData(session.getSessionToken(), experimentId, true);
+            assertEquals(dataSets.size(), 9);
+        } else
+        {
+            try
+            {
+                commonServer.listExperimentExternalData(session.getSessionToken(), experimentId, true);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListDataSetRelationshipsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        TechId parentId = new TechId(28L); // VALIDATIONS_PARENT-28
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<AbstractExternalData> children =
+                    commonServer.listDataSetRelationships(session.getSessionToken(), parentId, DataSetRelationshipRole.PARENT);
+            assertEntities("[VALIDATIONS_IMPOS-27]", children);
+        } else
+        {
+            try
+            {
+                commonServer.listDataSetRelationships(session.getSessionToken(), parentId, DataSetRelationshipRole.PARENT);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testGetDataSetInfoWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        TechId dataSetId = new TechId(41L); // 20120628092259000-41
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            AbstractExternalData dataSet = commonServer.getDataSetInfo(session.getSessionToken(), dataSetId);
+            assertNotNull(dataSet);
+            assertEquals(dataSet.getCode(), "20120628092259000-41");
+        } else
+        {
+            try
+            {
+                commonServer.getDataSetInfo(session.getSessionToken(), dataSetId);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListRelatedDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        BasicEntityInformationHolder experiment = new BasicEntityInformationHolder(EntityKind.EXPERIMENT, null, null, 23L, null); // /TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST
+        DataSetRelatedEntities related = new DataSetRelatedEntities(Arrays.asList(experiment));
+
+        List<AbstractExternalData> dataSets = commonServer.listRelatedDataSets(session.getSessionToken(), related, false);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            assertEquals(dataSets.size(), 9);
+        } else
+        {
+            assertEquals(dataSets.size(), 0);
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListRelatedDataSetsOnBehalfOfUserWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(TEST_USER, PASSWORD);
+
+        BasicEntityInformationHolder experiment = new BasicEntityInformationHolder(EntityKind.EXPERIMENT, null, null, 23L, null); // /TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST
+        DataSetRelatedEntities related = new DataSetRelatedEntities(Arrays.asList(experiment));
+
+        List<AbstractExternalData> dataSets =
+                commonServer.listRelatedDataSetsOnBehalfOfUser(session.getSessionToken(), related, false, user.getUserId());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            assertEquals(dataSets.size(), 9);
+        } else
+        {
+            assertEquals(dataSets.size(), 0);
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testDeleteDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+        TechId dataSetId = new TechId(41L);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            commonServer.deleteDataSets(session.getSessionToken(), Arrays.asList(dataSetCode), "test reason", DeletionType.TRASH, true);
+            try
+            {
+                commonServer.getDataSetInfo(session.getSessionToken(), dataSetId);
+                fail();
+            } catch (UserFailureException e)
+            {
+                assertEquals(e.getMessage(), "Data set with ID '41' does not exist.");
+            }
+        } else
+        {
+            try
+            {
+                commonServer.deleteDataSets(session.getSessionToken(), Arrays.asList(dataSetCode), "test reason", DeletionType.TRASH, true);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testUploadDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+        DataSetUploadContext uploadContext = new DataSetUploadContext();
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            commonServer.uploadDataSets(session.getSessionToken(), Arrays.asList(dataSetCode), uploadContext);
+        } else
+        {
+            try
+            {
+                commonServer.uploadDataSets(session.getSessionToken(), Arrays.asList(dataSetCode), uploadContext);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testCreateReportFromDatasetsWithServiceKeyWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+        String serviceKey = "I-DONT-EXIST";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            try
+            {
+                commonServer.createReportFromDatasets(session.getSessionToken(), serviceKey, Arrays.asList(dataSetCode));
+            } catch (Exception e)
+            {
+                assertEquals(e.getMessage(), "Data store 'STANDARD' does not have '" + serviceKey + "' report configured.");
+            }
+        } else
+        {
+            try
+            {
+                commonServer.createReportFromDatasets(session.getSessionToken(), serviceKey, Arrays.asList(dataSetCode));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testCreateReportFromDatasetsWithServiceDescriptionWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+        DatastoreServiceDescription serviceDescription = DatastoreServiceDescription.reporting(null, null, new String[] {}, "I-DONT-EXIST", null);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            try
+            {
+                commonServer.createReportFromDatasets(session.getSessionToken(), serviceDescription, Arrays.asList(dataSetCode));
+            } catch (Exception e)
+            {
+                assertEquals(e.getMessage(), "Cannot find the data store " + serviceDescription.getDatastoreCode());
+            }
+        } else
+        {
+            try
+            {
+                commonServer.createReportFromDatasets(session.getSessionToken(), serviceDescription, Arrays.asList(dataSetCode));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testProcessDatasetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+        DatastoreServiceDescription serviceDescription = DatastoreServiceDescription.processing("I-DONT-EXIST", null, new String[] {}, "STANDARD");
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            try
+            {
+                commonServer.processDatasets(session.getSessionToken(), serviceDescription, Arrays.asList(dataSetCode));
+            } catch (Exception e)
+            {
+                assertEquals(e.getMessage(),
+                        "Data store 'STANDARD' does not have '" + serviceDescription.getKey() + "' processing plugin configured.");
+            }
+        } else
+        {
+            try
+            {
+                commonServer.processDatasets(session.getSessionToken(), serviceDescription, Arrays.asList(dataSetCode));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testArchiveDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            commonServer.archiveDatasets(session.getSessionToken(), Arrays.asList(dataSetCode), false);
+        } else
+        {
+            try
+            {
+                commonServer.archiveDatasets(session.getSessionToken(), Arrays.asList(dataSetCode), false);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testUnarchiveDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            commonServer.unarchiveDatasets(session.getSessionToken(), Arrays.asList(dataSetCode));
+        } else
+        {
+            try
+            {
+                commonServer.unarchiveDatasets(session.getSessionToken(), Arrays.asList(dataSetCode));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testLockDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            commonServer.lockDatasets(session.getSessionToken(), Arrays.asList(dataSetCode));
+        } else
+        {
+            try
+            {
+                commonServer.lockDatasets(session.getSessionToken(), Arrays.asList(dataSetCode));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testUnlockDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            commonServer.unlockDatasets(session.getSessionToken(), Arrays.asList(dataSetCode));
+        } else
+        {
+            try
+            {
+                commonServer.unlockDatasets(session.getSessionToken(), Arrays.asList(dataSetCode));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testRetrieveLinkFromDataSetWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContextDTO session = commonServer.tryAuthenticate(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+        DatastoreServiceDescription serviceDescription = DatastoreServiceDescription.reporting(null, null, new String[] {}, "I-DONT-EXIST", null);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            try
+            {
+                commonServer.retrieveLinkFromDataSet(session.getSessionToken(), serviceDescription, dataSetCode);
+            } catch (Exception e)
+            {
+                assertEquals(e.getMessage(), "Cannot find the data store " + serviceDescription.getDatastoreCode());
+            }
+        } else
+        {
+            try
+            {
+                commonServer.retrieveLinkFromDataSet(session.getSessionToken(), serviceDescription, dataSetCode);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
     private void assertAssignedPropertyTypes(String expected, EntityType entityType)
     {
         List<? extends EntityTypePropertyType<?>> propTypes = entityType.getAssignedPropertyTypes();
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationChangingServiceTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationChangingServiceTest.java
index bab8a91665d..d5de1ccb7fd 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationChangingServiceTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationChangingServiceTest.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.systemtest.api.v1;
 
+import static org.testng.Assert.fail;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertNotNull;
@@ -27,15 +28,15 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 
-import junit.framework.Assert;
-
 import org.hibernate.Session;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.common.exceptions.AuthorizationFailureException;
-import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.common.test.AssertionUtil;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.SessionContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.OpenBISHibernateTransactionManager;
 import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.IGeneralInformationChangingService;
@@ -55,6 +56,7 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Vocabulary;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.id.dataset.DataSetCodeId;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.id.experiment.ExperimentIdentifierId;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.id.material.MaterialCodeAndTypeCodeId;
+import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.id.metaproject.IMetaprojectId;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.id.metaproject.MetaprojectIdentifierId;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.id.metaproject.MetaprojectTechIdId;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.id.sample.SampleIdentifierId;
@@ -62,12 +64,17 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Metaproject;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewETPTAssignment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleParentWithDerived;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTerm;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTermReplacement;
 import ch.systemsx.cisd.openbis.systemtest.PropertyHistory;
 import ch.systemsx.cisd.openbis.systemtest.SystemTestCase;
+import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 import ch.systemsx.cisd.openbis.util.GeneralInformationServiceUtil;
 
+import junit.framework.Assert;
+
 /**
  * @author Franz-Josef Elmer
  */
@@ -121,7 +128,7 @@ public class GeneralInformationChangingServiceTest extends SystemTestCase
         assertProperties("[ANY_MATERIAL: 1 (GENE), BACTERIUM: BACTERIUM-Y (BACTERIUM), "
                 + "COMMENT: extremely simple stuff, DESCRIPTION: hello example, GENDER: FEMALE, "
                 + "ORGANISM: DOG, SIZE: 42]", localCommonServer.getSampleInfo(sessionToken, id)
-                .getParent());
+                        .getParent());
 
         List<PropertyHistory> history = getSamplePropertiesHistory(id.getId());
         assertEquals(
@@ -207,8 +214,8 @@ public class GeneralInformationChangingServiceTest extends SystemTestCase
         newETPTAssignment.setShowRawValue(true);
         localCommonServer.assignPropertyType(sessionToken,
                 newETPTAssignment);
-        //we clear the hibernateSession because assignPropertyType
-        //method executes sqls outside hibernate session
+        // we clear the hibernateSession because assignPropertyType
+        // method executes sqls outside hibernate session
         Session hibernateSession = getHibernateSession();
         hibernateSession.clear();
 
@@ -669,6 +676,315 @@ public class GeneralInformationChangingServiceTest extends SystemTestCase
         testDeleteTrash(new DataSetDeleteAction(), new DataSetListDeletedAction());
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testDeleteDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String adminSession = generalInformationService.tryToAuthenticateForAllServices(TEST_USER, PASSWORD);
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+        String reason = "test reason";
+
+        List<DataSet> dataSets = generalInformationService.getDataSetMetaData(adminSession, Arrays.asList(dataSetCode));
+        assertEquals(1, dataSets.size());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            generalInformationChangingService.deleteDataSets(session, Arrays.asList(dataSetCode), reason, DeletionType.TRASH);
+
+            dataSets = generalInformationService.getDataSetMetaData(adminSession, Arrays.asList(dataSetCode));
+            assertEquals(0, dataSets.size());
+        } else
+        {
+            try
+            {
+                generalInformationChangingService.deleteDataSets(session, Arrays.asList(dataSetCode), reason, DeletionType.TRASH);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testUpdateSamplePropertiesWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        long sampleId = 1054L; // /TEST-SPACE/FV-TEST
+        String propertyCode = "COMMENT";
+        String propertyValue = "test comment";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            SampleParentWithDerived sample = commonServer.getSampleInfo(session, new TechId(sampleId));
+            assertEquals(sample.getParent().getProperties().size(), 1);
+
+            generalInformationChangingService.updateSampleProperties(session, sampleId, Collections.singletonMap(propertyCode, propertyValue));
+
+            sample = commonServer.getSampleInfo(session, new TechId(sampleId));
+            assertEquals(sample.getParent().getProperties().size(), 2);
+        } else
+        {
+            try
+            {
+                generalInformationChangingService.updateSampleProperties(session, sampleId, Collections.singletonMap(propertyCode, propertyValue));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testAddToMetaprojectWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        Metaproject metaproject = new Metaproject();
+        metaproject.setName("TEST_ADD_TO_METAPROJECT");
+        metaproject = commonServer.registerMetaproject(session, metaproject);
+
+        IMetaprojectId metaprojectId = new MetaprojectTechIdId(metaproject.getId());
+
+        MetaprojectAssignmentsIds assignments = new MetaprojectAssignmentsIds();
+        assignments.addExperiment(new ExperimentIdentifierId("/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST"));
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            generalInformationChangingService.addToMetaproject(session, metaprojectId, assignments);
+        } else
+        {
+            try
+            {
+                generalInformationChangingService.addToMetaproject(session, metaprojectId, assignments);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testRemoveFromMetaprojectWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        Metaproject metaproject = new Metaproject();
+        metaproject.setName("TEST_REMOVE_FROM_METAPROJECT");
+        metaproject = commonServer.registerMetaproject(session, metaproject);
+
+        IMetaprojectId metaprojectId = new MetaprojectTechIdId(metaproject.getId());
+
+        MetaprojectAssignmentsIds assignments = new MetaprojectAssignmentsIds();
+        assignments.addMaterial(new MaterialCodeAndTypeCodeId("VIRUS1", "VIRUS"));
+
+        generalInformationChangingService.addToMetaproject(session, metaprojectId, assignments);
+        generalInformationChangingService.removeFromMetaproject(session, metaprojectId, assignments);
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testRegisterSamplesWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContext session = commonClientService.tryToLogin(user.getUserId(), PASSWORD);
+
+        String sampleType = "CELL_PLATE";
+
+        uploadFile("testRegisterSamplesWithProjectAuthorization.txt",
+                "identifier\texperiment\tCOMMENT\n"
+                        + "/TEST-SPACE/PA_UPLOAD\t/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST\ttest comment\n");
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            generalInformationChangingService.registerSamples(session.getSessionID(), sampleType, SESSION_KEY, null);
+        } else
+        {
+            try
+            {
+                generalInformationChangingService.registerSamples(session.getSessionID(), sampleType, SESSION_KEY, null);
+                fail();
+            } catch (UserFailureException e)
+            {
+                AssertionUtil.assertMatches(".*does not have enough privileges.*", e.getMessage());
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testUpdateSamplesWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContext session = commonClientService.tryToLogin(user.getUserId(), PASSWORD);
+
+        String sampleType = "CELL_PLATE";
+
+        uploadFile("testUpdateSamplesWithProjectAuthorization.txt",
+                "identifier\tCOMMENT\n"
+                        + "/TEST-SPACE/FV-TEST\tupdated comment\n");
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            generalInformationChangingService.updateSamples(session.getSessionID(), sampleType, SESSION_KEY, null);
+        } else
+        {
+            try
+            {
+                generalInformationChangingService.updateSamples(session.getSessionID(), sampleType, SESSION_KEY, null);
+                fail();
+            } catch (UserFailureException e)
+            {
+                AssertionUtil.assertMatches(".*does not have enough privileges.*", e.getMessage());
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testUploadedSamplesInfoWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        SessionContext session = commonClientService.tryToLogin(user.getUserId(), PASSWORD);
+
+        String sampleType = "CELL_PLATE";
+
+        uploadFile("testUploadedSamplesInfoWithProjectAuthorization.txt",
+                "identifier\texperiment\tCOMMENT\n"
+                        + "/TEST-SPACE/PA_UPLOAD\t/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST\ttest comment\n");
+
+        // there are no checks on what has been uploaded before the uploaded data is actually used in the registration or update
+        generalInformationChangingService.uploadedSamplesInfo(session.getSessionID(), sampleType, SESSION_KEY);
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testDeleteProjectsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        Long projectId = 7L; // /TEST-SPACE/PROJECT-TO-DELETE
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            generalInformationChangingService.deleteProjects(session, Arrays.asList(projectId), "test reason");
+        } else
+        {
+            try
+            {
+                generalInformationChangingService.deleteProjects(session, Arrays.asList(projectId), "test reason");
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testDeleteExperimentsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String adminSession = generalInformationService.tryToAuthenticateForAllServices(TEST_USER, PASSWORD);
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        NewExperiment newExperiment = new NewExperiment();
+        newExperiment.setExperimentTypeCode("DELETION_TEST");
+        newExperiment.setIdentifier("/TEST-SPACE/TEST-PROJECT/EXPERIMENT-TO-DELETE");
+
+        ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment experiment =
+                genericServer.registerExperiment(adminSession, newExperiment, Arrays.asList());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            generalInformationChangingService.deleteExperiments(session, Arrays.asList(experiment.getId()), "test reason", DeletionType.TRASH);
+        } else
+        {
+            try
+            {
+                generalInformationChangingService.deleteExperiments(session, Arrays.asList(experiment.getId()), "test reason", DeletionType.TRASH);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testDeleteSamplesWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        Long sampleId = 1061L; // /TEST-SPACE/SAMPLE-TO-DELETE
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            generalInformationChangingService.deleteSamples(session, Arrays.asList(sampleId), "test reason", DeletionType.TRASH);
+        } else
+        {
+            try
+            {
+                generalInformationChangingService.deleteSamples(session, Arrays.asList(sampleId), "test reason", DeletionType.TRASH);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testRevertDeletionsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String adminSession = generalInformationService.tryToAuthenticateForAllServices(TEST_USER, PASSWORD);
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        Long sampleId = 1061L; // /TEST-SPACE/SAMPLE-TO-DELETE
+
+        generalInformationChangingService.deleteSamples(adminSession, Arrays.asList(sampleId), "test reason", DeletionType.TRASH);
+        List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion> deletions = commonServer.listDeletions(adminSession, true);
+
+        ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion deletion = deletions.get(deletions.size() - 1);
+        assertEquals("SAMPLE-TO-DELETE", deletion.getDeletedEntities().get(0).getCode());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            generalInformationChangingService.revertDeletions(session, Arrays.asList(deletion.getId()));
+        } else
+        {
+            try
+            {
+                generalInformationChangingService.revertDeletions(session, Arrays.asList(deletion.getId()));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testDeletePermanentlyWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String adminSession = generalInformationService.tryToAuthenticateForAllServices(TEST_USER, PASSWORD);
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        Long sampleId = 1061L; // /TEST-SPACE/SAMPLE-TO-DELETE
+
+        generalInformationChangingService.deleteSamples(adminSession, Arrays.asList(sampleId), "test reason", DeletionType.TRASH);
+        List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion> deletions = commonServer.listDeletions(adminSession, true);
+
+        ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion deletion = deletions.get(deletions.size() - 1);
+        assertEquals("SAMPLE-TO-DELETE", deletion.getDeletedEntities().get(0).getCode());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            generalInformationChangingService.deletePermanently(session, Arrays.asList(deletion.getId()));
+        } else
+        {
+            try
+            {
+                generalInformationChangingService.deletePermanently(session, Arrays.asList(deletion.getId()));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+            }
+        }
+    }
+
     private class ProjectDeleteAction implements DeleteAction<Project>
     {
         @Override
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java
index da61923c671..b04066ce342 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java
@@ -1968,13 +1968,13 @@ public class GeneralInformationServiceTest extends SystemTestCase
     public void testFilterExperimentVisibleToUserWithProjectAuthorization(ProjectAuthorizationUser user)
     {
         String session = generalInformationService.tryToAuthenticateForAllServices(TEST_USER, PASSWORD);
-        
+
         SearchCriteria criteria = new SearchCriteria();
         criteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.SPACE, "TEST-SPACE"));
-        
+
         List<Experiment> experiments = generalInformationService.searchForExperiments(session, criteria);
         List<Experiment> filteredExperiments = generalInformationService.filterExperimentsVisibleToUser(session, experiments, user.getUserId());
-        
+
         if (user.isInstanceUser() || user.isTestSpaceUser())
         {
             assertEntities(
@@ -1988,14 +1988,14 @@ public class GeneralInformationServiceTest extends SystemTestCase
             assertEntities("[]", filteredExperiments);
         }
     }
-    
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
     public void testListProjectsWithProjectAuthorization(ProjectAuthorizationUser user)
     {
         String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
-        
+
         List<Project> projects = generalInformationService.listProjects(session);
-        
+
         if (user.isInstanceUser())
         {
             assertEntities(
@@ -2019,14 +2019,14 @@ public class GeneralInformationServiceTest extends SystemTestCase
             assertEntities("[]", projects);
         }
     }
-    
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
     public void testListProjectsOnBehalfOfUserWithProjectAuthorization(ProjectAuthorizationUser user)
     {
         String session = generalInformationService.tryToAuthenticateForAllServices(TEST_USER, PASSWORD);
-        
+
         List<Project> projects = generalInformationService.listProjectsOnBehalfOfUser(session, user.getUserId());
-        
+
         if (user.isInstanceUser())
         {
             assertEntities(
@@ -2050,14 +2050,14 @@ public class GeneralInformationServiceTest extends SystemTestCase
             assertEntities("[]", projects);
         }
     }
-    
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
     public void testListAttachmentForProjectWithProjectAuthorization(ProjectAuthorizationUser user)
     {
         String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
-        
+
         ProjectIdentifierId projectId = new ProjectIdentifierId("/TEST-SPACE/TEST-PROJECT");
-        
+
         if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
         {
             List<Attachment> attachments =
@@ -2076,7 +2076,7 @@ public class GeneralInformationServiceTest extends SystemTestCase
             }
         }
     }
-    
+
     @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
     public void testListAttachmentsForExperimentWithProjectAuthorization(ProjectAuthorizationUser user)
     {
@@ -2740,6 +2740,249 @@ public class GeneralInformationServiceTest extends SystemTestCase
         generalInformationService.logout(spaceUserSessionToken);
     }
 
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListDataSetsWithSamplesWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<DataSet> dataSets = generalInformationService.listDataSets(session, Arrays.asList(createFvTestSample()));
+            assertEquals(1, dataSets.size());
+            assertEquals("20120628092259000-41", dataSets.get(0).getCode());
+        } else
+        {
+            try
+            {
+                generalInformationService.listDataSets(session, Arrays.asList(createFvTestSample()));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListDataSetsWithSamplesAndConnectionsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<DataSet> dataSets = generalInformationService.listDataSets(session, Arrays.asList(createFvTestSample()), null);
+            assertEquals(1, dataSets.size());
+            assertEquals("20120628092259000-41", dataSets.get(0).getCode());
+        } else
+        {
+            try
+            {
+                generalInformationService.listDataSets(session, Arrays.asList(createFvTestSample()), null);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListDataSetsForSampleWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<DataSet> dataSets = generalInformationService.listDataSetsForSample(session, createFvTestSample(), true);
+            assertEquals(1, dataSets.size());
+            assertEquals("20120628092259000-41", dataSets.get(0).getCode());
+        } else
+        {
+            try
+            {
+                generalInformationService.listDataSetsForSample(session, createFvTestSample(), true);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListDataSetsOnBehalfOfUserWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(TEST_USER, PASSWORD);
+
+        List<DataSet> dataSets =
+                generalInformationService.listDataSetsOnBehalfOfUser(session, Arrays.asList(createFvTestSample()), null, user.getUserId());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            assertEquals(1, dataSets.size());
+            assertEquals("20120628092259000-41", dataSets.get(0).getCode());
+        } else
+        {
+            assertEquals(0, dataSets.size());
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListDataSetsForExperimentWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<DataSet> dataSets =
+                    generalInformationService.listDataSetsForExperiments(session, Arrays.asList(createExpSpaceTestExperiment()), null);
+            assertEquals(9, dataSets.size());
+        } else
+        {
+            try
+            {
+                generalInformationService.listDataSetsForExperiments(session, Arrays.asList(createExpSpaceTestExperiment()), null);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testListDataSetsForExperimentsOnBehalfOfUserWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(TEST_USER, PASSWORD);
+
+        List<DataSet> dataSets =
+                generalInformationService.listDataSetsForExperimentsOnBehalfOfUser(session, Arrays.asList(createExpSpaceTestExperiment()), null,
+                        user.getUserId());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            assertEquals(9, dataSets.size());
+        } else
+        {
+            assertEquals(0, dataSets.size());
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testGetDataSetMetaDataWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<DataSet> dataSets = generalInformationService.getDataSetMetaData(session, Arrays.asList(dataSetCode));
+            assertEquals(1, dataSets.size());
+            assertEquals(dataSetCode, dataSets.get(0).getCode());
+        } else
+        {
+            try
+            {
+                generalInformationService.getDataSetMetaData(session, Arrays.asList(dataSetCode));
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testGetDataSetMetaDataWithFetchOptionsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        String dataSetCode = "20120628092259000-41";
+        EnumSet<DataSetFetchOption> fetchOptions = EnumSet.noneOf(DataSetFetchOption.class);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            List<DataSet> dataSets = generalInformationService.getDataSetMetaData(session, Arrays.asList(dataSetCode), fetchOptions);
+            assertEquals(1, dataSets.size());
+            assertEquals(dataSetCode, dataSets.get(0).getCode());
+        } else
+        {
+            try
+            {
+                generalInformationService.getDataSetMetaData(session, Arrays.asList(dataSetCode), fetchOptions);
+                fail();
+            } catch (AuthorizationFailureException e)
+            {
+                // expected
+            }
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testSearchForDataSetsWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(user.getUserId(), PASSWORD);
+
+        SearchCriteria criteria = new SearchCriteria();
+        criteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE, "20120628092259000-41"));
+
+        List<DataSet> dataSets = generalInformationService.searchForDataSets(session, criteria);
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            assertEquals(1, dataSets.size());
+            assertEquals("20120628092259000-41", dataSets.get(0).getCode());
+        } else
+        {
+            assertEquals(0, dataSets.size());
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testSearchForDataSetsOnBehalfOfUserWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(TEST_USER, PASSWORD);
+
+        SearchCriteria criteria = new SearchCriteria();
+        criteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE, "20120628092259000-41"));
+
+        List<DataSet> dataSets = generalInformationService.searchForDataSetsOnBehalfOfUser(session, criteria, user.getUserId());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            assertEquals(1, dataSets.size());
+            assertEquals("20120628092259000-41", dataSets.get(0).getCode());
+        } else
+        {
+            assertEquals(0, dataSets.size());
+        }
+    }
+
+    @Test(dataProviderClass = ProjectAuthorizationUser.class, dataProvider = ProjectAuthorizationUser.PROVIDER)
+    public void testFilterDataSetsVisibleToUserWithProjectAuthorization(ProjectAuthorizationUser user)
+    {
+        String session = generalInformationService.tryToAuthenticateForAllServices(TEST_USER, PASSWORD);
+
+        SearchCriteria criteria = new SearchCriteria();
+        criteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE, "20120628092259000-41"));
+
+        List<DataSet> dataSets = generalInformationService.searchForDataSets(session, criteria);
+
+        assertEquals(1, dataSets.size());
+
+        List<DataSet> filteredDataSets = generalInformationService.filterDataSetsVisibleToUser(session, dataSets, user.getUserId());
+
+        if (user.isInstanceUserOrTestSpaceUserOrEnabledTestProjectUser())
+        {
+            assertEquals(1, filteredDataSets.size());
+            assertEquals("20120628092259000-41", dataSets.get(0).getCode());
+        } else
+        {
+            assertEquals(0, filteredDataSets.size());
+        }
+    }
+
     private void sortDataSets(List<DataSet> dataSets)
     {
         Collections.sort(dataSets, new Comparator<DataSet>()
@@ -2770,4 +3013,29 @@ public class GeneralInformationServiceTest extends SystemTestCase
         }
     }
 
+    private static Sample createFvTestSample()
+    {
+        SampleInitializer initializer = new SampleInitializer();
+        initializer.setId(1054L);
+        initializer.setPermId("201206191219327-1054");
+        initializer.setCode("FV-TEST");
+        initializer.setIdentifier("/TEST-SPACE/FV-TEST");
+        initializer.setSampleTypeId(3L);
+        initializer.setSampleTypeCode("CELL_PLATE");
+        initializer.setRegistrationDetails(new EntityRegistrationDetails(new EntityRegistrationDetailsInitializer()));
+        return new Sample(initializer);
+    }
+
+    private static Experiment createExpSpaceTestExperiment()
+    {
+        ExperimentInitializer initializer = new ExperimentInitializer();
+        initializer.setId(23L);
+        initializer.setPermId("201206190940555-1032");
+        initializer.setCode("EXP-SPACE-TEST");
+        initializer.setIdentifier("/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST");
+        initializer.setExperimentTypeCode("SIRNA_HCS");
+        initializer.setRegistrationDetails(new EntityRegistrationDetails(new EntityRegistrationDetailsInitializer()));
+        return new Experiment(initializer);
+    }
+
 }
-- 
GitLab