diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/AttachmentSynchronizationTaskExecutor.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/AttachmentSynchronizationTaskExecutor.java
index 7aa70fadfda80b420fe8df945cfb22d12d8a8a0b..de9c9130a28fe5d1d7724b50df87ee0725233ee5 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/AttachmentSynchronizationTaskExecutor.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/AttachmentSynchronizationTaskExecutor.java
@@ -26,6 +26,8 @@ import java.util.Map;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.attachment.Attachment;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentPermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.ProjectPermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SamplePermId;
 import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.common.ServiceFinderUtils;
 import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.config.SyncConfig;
 import ch.systemsx.cisd.common.concurrent.ITaskExecutor;
@@ -39,7 +41,12 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Identifier;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewAttachment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewProject;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifierFactory;
 
 /**
  * 
@@ -53,8 +60,6 @@ final class AttachmentSynchronizationTaskExecutor implements ITaskExecutor<Ident
     private final SyncConfig config;
 
     private final IEncapsulatedOpenBISService service;
-    
-    private AttachmentsOperationsHandler attachmentsOperationsHandler;
 
     public AttachmentSynchronizationTaskExecutor(IEncapsulatedOpenBISService service, Date lastSyncTimestamp, SyncConfig config)
     {
@@ -69,12 +74,29 @@ final class AttachmentSynchronizationTaskExecutor implements ITaskExecutor<Ident
         TechId techId = null;
         ICommonServer commonServer = ServiceFinderUtils.getCommonServer(ServiceProvider.getConfigProvider().getOpenBisServerUrl());
         String localSessionToken = ServiceFinderUtils.login(commonServer, config.getHarvesterUser(), config.getHarvesterPass());
+        IAttachmentsOperationsHandler attachmentsOperationsHandler = null;
         if (item instanceof NewExperiment)
         {
             Experiment experiment = service.tryGetExperiment(ExperimentIdentifierFactory.parse(item.getIdentifier()));
             techId = new TechId(experiment.getId());
             attachmentsOperationsHandler = new ExperimentAttachmentsOperationsHandler(config, commonServer, localSessionToken);
         }
+        else if (item instanceof NewSample)
+        {
+            Sample sample = service.tryGetSampleByPermId(item.getPermID());
+            techId = new TechId(sample.getId());
+            attachmentsOperationsHandler = new SampleAttachmentsOperationsHandler(config, commonServer, localSessionToken);
+        }
+        else if (item instanceof NewProject)
+        {
+            Project project = service.tryGetProject(ProjectIdentifierFactory.parse(item.getIdentifier()));
+            techId = new TechId(project.getId());
+            attachmentsOperationsHandler = new ProjectAttachmentsOperationsHandler(config, commonServer, localSessionToken);
+        }
+        else
+        {
+            return Status.createError("Attachments can be synchronized for only Projects, Experiments and Samples");
+        }
         List<Attachment> incomingAttachments = attachmentsOperationsHandler.listAttachmentsDataSource(config, item.getPermID());
 
         // place the incoming attachments in a map
@@ -85,7 +107,7 @@ final class AttachmentSynchronizationTaskExecutor implements ITaskExecutor<Ident
         }
 
         List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment> existingAttachments =
-                attachmentsOperationsHandler.listAttachmentsHarvester(item.getIdentifier());
+                attachmentsOperationsHandler.listAttachmentsHarvester(item.getPermID());
         Map<String, ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment> existingAttachmentMap =
                 new HashMap<String, ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment>();
 
@@ -109,14 +131,14 @@ final class AttachmentSynchronizationTaskExecutor implements ITaskExecutor<Ident
                 if (incoming.getVersion() < version)
                 {
                     // Harvester has a later version of the attachment. Delete it from harvester
-                    replaceAttachment(techId, incoming);
+                    replaceAttachment(techId, incoming, attachmentsOperationsHandler);
                 }
                 else if (incoming.getVersion() == version)
                 {
                     // check last sync date and meta data
                     if (incoming.getRegistrationDate().after(lastSyncTimestamp))
                     {
-                        replaceAttachment(techId, incoming);
+                        replaceAttachment(techId, incoming, attachmentsOperationsHandler);
                     }
                     else
                     {
@@ -150,7 +172,7 @@ final class AttachmentSynchronizationTaskExecutor implements ITaskExecutor<Ident
                 attachmentsOperationsHandler.deleteAttachment(techId, existing.getFileName());
             }
         }
-        return null;
+        return Status.OK;
     }
 
     private boolean equalsNullable(String s1OrNull, String s2OrNull)
@@ -167,13 +189,13 @@ final class AttachmentSynchronizationTaskExecutor implements ITaskExecutor<Ident
         }
     }
 
-    private void replaceAttachment(TechId techId, Attachment incoming)
+    private void replaceAttachment(TechId techId, Attachment incoming, IAttachmentsOperationsHandler attachmentsOperationsHandler)
     {
         attachmentsOperationsHandler.deleteAttachment(techId, incoming.getFileName());
         addAttachments(incoming, 1, techId, attachmentsOperationsHandler);
     }
 
-    private void addAttachments(Attachment attachment, int fromVersion, TechId techId, AttachmentsOperationsHandler handler)
+    private void addAttachments(Attachment attachment, int fromVersion, TechId techId, IAttachmentsOperationsHandler handler)
     {
 
         Integer version = attachment.getVersion();
@@ -201,11 +223,11 @@ final class AttachmentSynchronizationTaskExecutor implements ITaskExecutor<Ident
     }
 }
 
-interface AttachmentsOperationsHandler
+interface IAttachmentsOperationsHandler
 {
     List<Attachment> listAttachmentsDataSource(SyncConfig config, String permId);
     
-    List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment> listAttachmentsHarvester(String identifier);
+    List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment> listAttachmentsHarvester(String permId);
     
     void addAttachment(TechId techId, NewAttachment attachment);
 
@@ -214,7 +236,7 @@ interface AttachmentsOperationsHandler
     void updateAttachment(TechId experimentId, ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment attachment);
 }
 
-class ExperimentAttachmentsOperationsHandler implements AttachmentsOperationsHandler
+abstract class AbstractEntityAttachmentsOperationsHandler implements IAttachmentsOperationsHandler
 {
     final ICommonServer commonServer;
 
@@ -222,18 +244,36 @@ class ExperimentAttachmentsOperationsHandler implements AttachmentsOperationsHan
 
     final SyncConfig config;
 
-    /**
-     * @param config
-     * @param commonServer
-     * @param localSessionToken
-     */
-    public ExperimentAttachmentsOperationsHandler(SyncConfig config, ICommonServer commonServer, String sessionToken)
+    AbstractEntityAttachmentsOperationsHandler(SyncConfig config, ICommonServer commonServer, String sessionToken)
     {
         this.commonServer = commonServer;
         this.sessionToken = sessionToken;
         this.config = config;
     }
 
+    @Override
+    public abstract List<Attachment> listAttachmentsDataSource(SyncConfig config, String permId);
+
+    @Override
+    public abstract List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment> listAttachmentsHarvester(String permId);
+
+    @Override
+    public abstract void addAttachment(TechId techId, NewAttachment attachment);
+
+    @Override
+    public abstract void deleteAttachment(TechId experimentId, String fileName);
+    
+    @Override
+    public abstract void updateAttachment(TechId experimentId, ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment attachment);
+}
+
+class ExperimentAttachmentsOperationsHandler extends AbstractEntityAttachmentsOperationsHandler
+{
+    ExperimentAttachmentsOperationsHandler(SyncConfig config, ICommonServer commonServer, String sessionToken)
+    {
+        super(config, commonServer, sessionToken);
+    }
+
     @Override
     public List<Attachment> listAttachmentsDataSource(SyncConfig config, String permId)
     {
@@ -243,10 +283,10 @@ class ExperimentAttachmentsOperationsHandler implements AttachmentsOperationsHan
     }
 
     @Override
-    public List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment> listAttachmentsHarvester(String identifier)
+    public List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment> listAttachmentsHarvester(String permId)
     {
         IEncapsulatedOpenBISService service = ServiceProvider.getOpenBISService();
-        Experiment experiment = service.tryGetExperiment(ExperimentIdentifierFactory.parse(identifier));
+        Experiment experiment = service.tryGetExperimentByPermId(permId);
         return service.listAttachments(AttachmentHolderKind.EXPERIMENT, experiment.getId());
     }
 
@@ -269,4 +309,92 @@ class ExperimentAttachmentsOperationsHandler implements AttachmentsOperationsHan
     {
         commonServer.updateExperimentAttachments(sessionToken, experimentId, attachment);
     }
+}
+
+class SampleAttachmentsOperationsHandler extends AbstractEntityAttachmentsOperationsHandler
+{
+    SampleAttachmentsOperationsHandler(SyncConfig config, ICommonServer commonServer, String sessionToken)
+    {
+        super(config, commonServer, sessionToken);
+    }
+
+    @Override
+    public List<Attachment> listAttachmentsDataSource(SyncConfig config, String permId)
+    {
+        V3Utils dssFileUtils = V3Utils.create(config.getDataSourceOpenbisURL(), config.getDataSourceDSSURL());
+        String sessionToken = dssFileUtils.login(config.getUser(), config.getPassword());
+        return dssFileUtils.getSampleAttachments(sessionToken, new SamplePermId(permId));
+    }
+
+    @Override
+    public List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment> listAttachmentsHarvester(String permId)
+    {
+        IEncapsulatedOpenBISService service = ServiceProvider.getOpenBISService();
+        Sample sample = service.tryGetSampleByPermId(permId);
+        return service.listAttachments(AttachmentHolderKind.SAMPLE, sample.getId());
+    }
+
+    @Override
+    public void addAttachment(TechId techId, NewAttachment attachment)
+    {
+        commonServer.addSampleAttachments(sessionToken, techId, attachment);
+    }
+
+    @Override
+    public void deleteAttachment(TechId sampleId, String fileName)
+    {
+        commonServer.deleteSampleAttachments(sessionToken, sampleId, Arrays.asList(fileName),
+                "Synchronization from data source " + config.getDataSourceAlias()
+                        + " Attachment no longer exists on data source.");
+    }
+
+    @Override
+    public void updateAttachment(TechId sampleId, ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment attachment)
+    {
+        commonServer.updateSampleAttachments(sessionToken, sampleId, attachment);
+    }
+}
+
+class ProjectAttachmentsOperationsHandler extends AbstractEntityAttachmentsOperationsHandler
+{
+    ProjectAttachmentsOperationsHandler(SyncConfig config, ICommonServer commonServer, String sessionToken)
+    {
+        super(config, commonServer, sessionToken);
+    }
+
+    @Override
+    public List<Attachment> listAttachmentsDataSource(SyncConfig config, String permId)
+    {
+        V3Utils dssFileUtils = V3Utils.create(config.getDataSourceOpenbisURL(), config.getDataSourceDSSURL());
+        String sessionToken = dssFileUtils.login(config.getUser(), config.getPassword());
+        return dssFileUtils.getProjectAttachments(sessionToken, new ProjectPermId(permId));
+    }
+
+    @Override
+    public List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment> listAttachmentsHarvester(String permId)
+    {
+        IEncapsulatedOpenBISService service = ServiceProvider.getOpenBISService();
+        Project project = service.tryGetProjectByPermId(permId);
+        return service.listAttachments(AttachmentHolderKind.PROJECT, project.getId());
+    }
+
+    @Override
+    public void addAttachment(TechId techId, NewAttachment attachment)
+    {
+        commonServer.addProjectAttachments(sessionToken, techId, attachment);
+    }
+
+    @Override
+    public void deleteAttachment(TechId projectId, String fileName)
+    {
+        commonServer.deleteProjectAttachments(sessionToken, projectId, Arrays.asList(fileName),
+                "Synchronization from data source " + config.getDataSourceAlias()
+                        + " Attachment no longer exists on data source.");
+    }
+
+    @Override
+    public void updateAttachment(TechId projectId, ch.systemsx.cisd.openbis.generic.shared.basic.dto.Attachment attachment)
+    {
+        commonServer.updateProjectAttachments(sessionToken, projectId, attachment);
+    }
 }
\ No newline at end of file
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java
index e3f13e43c0a3450eb272c2163dd7ef0c9bc64ee2..c502be29850eb891feedd1a04747b72eb5f0ef1c 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java
@@ -219,7 +219,7 @@ public class EntitySynchronizer
         operationLog.info("entity operation result: " + operationResult);
 
         operationLog.info("processing attachments...");
-        // processAttachments(entitiesWithAttachments);
+        processAttachments(entitiesWithAttachments);
 
         // register physical data sets without any hierarchy
         // Note that container/component and parent/child relationships are established post-reg.
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/V3Utils.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/V3Utils.java
index d83f38d770acde119544c30ee69c4cbb49251609..8e75f7d9cd76f31ab8e5c0662817ea342117704e 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/V3Utils.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/V3Utils.java
@@ -27,6 +27,12 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentFetchOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.fetchoptions.ProjectFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.IProjectId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId;
 import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi;
 import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.DataSetFile;
 import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadOptions;
@@ -79,9 +85,7 @@ public class V3Utils
         ExperimentFetchOptions fetchOptions = new ExperimentFetchOptions();
         fetchOptions.withAttachments().withContent();
         fetchOptions.withAttachments().withPreviousVersion().withPreviousVersionUsing(fetchOptions.withAttachments());
-        fetchOptions.withAttachments().withPreviousVersion().withContentUsing(fetchOptions.withAttachments().withContent());// attachmentFetchOptions.withContent();
-        // attachmentFetchOptions.withPreviousVersion().withPreviousVersionUsing(fetchOptions.withAttachments());
-        // .withContentUsing(attachmentFetchOptions.withContent());
+        fetchOptions.withAttachments().withPreviousVersion().withContentUsing(fetchOptions.withAttachments().withContent());
         Map<IExperimentId, Experiment> experiments = as.getExperiments(sessionToken, Arrays.asList(experimentId), fetchOptions);
         if(experiments.size() == 1) {
             Experiment experiment = experiments.get(experimentId);
@@ -90,6 +94,36 @@ public class V3Utils
         return null;
     }
 
+    public List<Attachment> getSampleAttachments(String sessionToken, ISampleId sampleId)
+    {
+        SampleFetchOptions fetchOptions = new SampleFetchOptions();
+        fetchOptions.withAttachments().withContent();
+        fetchOptions.withAttachments().withPreviousVersion().withPreviousVersionUsing(fetchOptions.withAttachments());
+        fetchOptions.withAttachments().withPreviousVersion().withContentUsing(fetchOptions.withAttachments().withContent());
+        Map<ISampleId, Sample> samples = as.getSamples(sessionToken, Arrays.asList(sampleId), fetchOptions);
+        if (samples.size() == 1)
+        {
+            Sample sample = samples.get(sampleId);
+            return sample.getAttachments();
+        }
+        return null;
+    }
+
+    public List<Attachment> getProjectAttachments(String sessionToken, IProjectId projectId)
+    {
+        ProjectFetchOptions fetchOptions = new ProjectFetchOptions();
+        fetchOptions.withAttachments().withContent();
+        fetchOptions.withAttachments().withPreviousVersion().withPreviousVersionUsing(fetchOptions.withAttachments());
+        fetchOptions.withAttachments().withPreviousVersion().withContentUsing(fetchOptions.withAttachments().withContent());
+        Map<IProjectId, Project> projects = as.getProjects(sessionToken, Arrays.asList(projectId), fetchOptions);
+        if (projects.size() == 1)
+        {
+            Project project = projects.get(projectId);
+            return project.getAttachments();
+        }
+        return null;
+    }
+
     public InputStream downloadFiles(String sessionToken, List<IDataSetFileId> fileIds, DataSetFileDownloadOptions options)
     {
         return dss.downloadFiles(sessionToken, fileIds, options);