diff --git a/src-db/database/sourcedata/AD_MESSAGE.xml b/src-db/database/sourcedata/AD_MESSAGE.xml
--- a/src-db/database/sourcedata/AD_MESSAGE.xml
+++ b/src-db/database/sourcedata/AD_MESSAGE.xml
@@ -78,7 +78,7 @@
 <!--FF873E6B5EEC4AD3BB49C5C429272E4D-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
 <!--FF873E6B5EEC4AD3BB49C5C429272E4D-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
 <!--FF873E6B5EEC4AD3BB49C5C429272E4D-->  <VALUE><![CDATA[OBAS3_InactiveConfiguration]]></VALUE>
-<!--FF873E6B5EEC4AD3BB49C5C429272E4D-->  <MSGTEXT><![CDATA[The attachment configuration is not active.]]></MSGTEXT>
+<!--FF873E6B5EEC4AD3BB49C5C429272E4D-->  <MSGTEXT><![CDATA[The storage configuration is not active.]]></MSGTEXT>
 <!--FF873E6B5EEC4AD3BB49C5C429272E4D-->  <MSGTYPE><![CDATA[W]]></MSGTYPE>
 <!--FF873E6B5EEC4AD3BB49C5C429272E4D-->  <AD_MODULE_ID><![CDATA[59893CC3B83B4157B5AA83D63909C9EC]]></AD_MODULE_ID>
 <!--FF873E6B5EEC4AD3BB49C5C429272E4D-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
diff --git a/src/org/openbravo/service/integration/amazon/s3/AmazonS3ClientProvider.java b/src/org/openbravo/service/integration/amazon/s3/AmazonS3ClientProvider.java
--- a/src/org/openbravo/service/integration/amazon/s3/AmazonS3ClientProvider.java
+++ b/src/org/openbravo/service/integration/amazon/s3/AmazonS3ClientProvider.java
@@ -1,6 +1,6 @@
 /*
  ************************************************************************************
- * Copyright (C) 2018 Openbravo S.L.U.
+ * Copyright (C) 2018-2019 Openbravo S.L.U.
  * Licensed under the Openbravo Commercial License version 1.0
  * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
  * or in the legal folder of this module distribution.
@@ -13,6 +13,7 @@
 import javax.enterprise.context.ApplicationScoped;
 
 import org.openbravo.base.weld.WeldUtils;
+import org.openbravo.dal.core.OBContext;
 import org.openbravo.service.integration.amazon.s3.attachments.AmazonS3AttachmentClient;
 import org.openbravo.service.integration.amazon.s3.storage.AmazonS3BatchTransferClient;
 import org.openbravo.service.integration.amazon.s3.storage.AmazonS3StorageClient;
@@ -24,8 +25,8 @@
 public class AmazonS3ClientProvider {
 
   private ConcurrentHashMap<String, AmazonS3AttachmentClient> s3AttachmentClients = new ConcurrentHashMap<>();
-
   private ConcurrentHashMap<String, AmazonS3StorageClient> s3StorageClients = new ConcurrentHashMap<>();
+  private ConcurrentHashMap<String, AmazonS3StorageClient> s3PermanentStorageClients = new ConcurrentHashMap<>();
 
   /**
    * @return the {@code AmazonS3ClientProvider} instance.
@@ -54,7 +55,7 @@
 
   /**
    * Gets the {@code AmazonS3StorageClient} instance that should be used to handle the permanent
-   * storage according to the {@code S3Configuration} whose search key is received as parameters.
+   * storage according to the {@code S3Configuration} whose search key is received as parameter.
    * 
    * @param searchKey
    *          The search key of the {@code S3Configuration}.
@@ -71,6 +72,24 @@
   }
 
   /**
+   * Gets the {@code AmazonS3StorageClient} instance that should be used to handle the storage of
+   * permanent files according to the storage configuration of the current client. If there is no
+   * such configuration for the current client, then the configuration at system level is taken, if
+   * any.
+   *
+   * @return the {@code AmazonS3StorageClient} instance that should be used to handle the storage of
+   *         permanent files for the current client.
+   */
+  public AmazonS3StorageClient getAmazonS3PermanentStorageClient() {
+    String clientId = OBContext.getOBContext().getCurrentClient().getId();
+    if (!s3PermanentStorageClients.containsKey(clientId)) {
+      AmazonS3StorageClient s3StorageClient = new AmazonS3StorageClient();
+      s3PermanentStorageClients.putIfAbsent(clientId, s3StorageClient);
+    }
+    return s3PermanentStorageClients.get(clientId);
+  }
+
+  /**
    * Gets the {@code AmazonS3BatchTransferClient} instance that should be used to handle the storage
    * according to the provided {@code S3Configuration}.
    * 
diff --git a/src/org/openbravo/service/integration/amazon/s3/attachments/AmazonS3AttachImplementation.java b/src/org/openbravo/service/integration/amazon/s3/attachments/AmazonS3AttachImplementation.java
--- a/src/org/openbravo/service/integration/amazon/s3/attachments/AmazonS3AttachImplementation.java
+++ b/src/org/openbravo/service/integration/amazon/s3/attachments/AmazonS3AttachImplementation.java
@@ -1,6 +1,6 @@
 /*
  ************************************************************************************
- * Copyright (C) 2018 Openbravo S.L.U.
+ * Copyright (C) 2018-2019 Openbravo S.L.U.
  * Licensed under the Openbravo Commercial License version 1.0
  * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
  * or in the legal folder of this module distribution.
@@ -10,9 +10,7 @@
 
 import java.io.File;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.Map;
-import java.util.UUID;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
@@ -20,6 +18,7 @@
 import org.apache.commons.io.FileUtils;
 import org.openbravo.base.exception.OBException;
 import org.openbravo.client.application.attachment.AttachImplementation;
+import org.openbravo.client.application.filestorage.TemporaryStorage;
 import org.openbravo.client.kernel.ComponentProvider;
 import org.openbravo.dal.core.OBContext;
 import org.openbravo.erpCommon.utility.OBMessageUtils;
@@ -63,7 +62,7 @@
     log.debug("Downloading attachment {} of record {}", attachment.getId(), attachment.getRecord());
     try {
       long t1 = System.currentTimeMillis();
-      Path path = getTempFilePath(attachment.getName());
+      Path path = TemporaryStorage.getInstance().create("", attachment.getName());
       getAmazonS3AttachmentClient().download(attachment, path);
       log.debug("Attachment {} downloaded in {} ms", attachment.getId(),
           (System.currentTimeMillis() - t1));
@@ -102,13 +101,9 @@
     return true;
   }
 
-  private Path getTempFilePath(String name) {
-    return Paths.get(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString(), name);
-  }
-
   private AmazonS3AttachmentClient getAmazonS3AttachmentClient() {
     String clientId = OBContext.getOBContext().getCurrentClient().getId();
     return s3clientProvider.getAmazonS3AttachmentClient(clientId);
   }
 
-}
\ No newline at end of file
+}
diff --git a/src/org/openbravo/service/integration/amazon/s3/attachments/AmazonS3AttachmentClient.java b/src/org/openbravo/service/integration/amazon/s3/attachments/AmazonS3AttachmentClient.java
--- a/src/org/openbravo/service/integration/amazon/s3/attachments/AmazonS3AttachmentClient.java
+++ b/src/org/openbravo/service/integration/amazon/s3/attachments/AmazonS3AttachmentClient.java
@@ -14,6 +14,7 @@
 
 import org.hibernate.criterion.Restrictions;
 import org.openbravo.client.application.attachment.CoreAttachImplementation;
+import org.openbravo.client.application.filestorage.StorageType;
 import org.openbravo.dal.core.OBContext;
 import org.openbravo.dal.service.OBCriteria;
 import org.openbravo.dal.service.OBDal;
@@ -30,7 +31,9 @@
 
   /** ID of the Amazon S3 Attachment Method **/
   public static final String S3_ATTACH_METHOD_ID = "32FC392D9ADA4A33BC90EB9850C9B156";
-  /** Name of the common parent virtual directory where the attachments will be stored in Amazon S3. **/
+  /**
+   * Name of the common parent virtual directory where the attachments will be stored in Amazon S3.
+   **/
   public static final String VIRTUAL_ROOT_DIRECTORY = "attachments";
 
   /**
@@ -48,11 +51,13 @@
     try {
       OBContext.setAdminMode(true);
       // Only one active attachment configuration is allowed per client.
-      OBCriteria<AttachmentConfig> criteria = OBDal.getInstance().createCriteria(
-          AttachmentConfig.class);
+      OBCriteria<AttachmentConfig> criteria = OBDal.getInstance()
+          .createCriteria(AttachmentConfig.class);
       criteria.add(Restrictions.eq(AttachmentConfig.PROPERTY_CLIENT + ".id", clientId));
-      criteria.add(Restrictions.eq(AttachmentConfig.PROPERTY_ATTACHMENTMETHOD + ".id",
-          S3_ATTACH_METHOD_ID));
+      criteria.add(
+          Restrictions.eq(AttachmentConfig.PROPERTY_ATTACHMENTMETHOD + ".id", S3_ATTACH_METHOD_ID));
+      criteria.add(
+          Restrictions.eq(AttachmentConfig.PROPERTY_STORAGETYPE, StorageType.ATTACHMENT.name()));
       AttachmentConfig attachmentConfiguration = (AttachmentConfig) criteria.uniqueResult();
       return attachmentConfiguration != null ? attachmentConfiguration.getObas3Configuration()
           : null;
diff --git a/src/org/openbravo/service/integration/amazon/s3/process/AmazonS3ValidationClient.java b/src/org/openbravo/service/integration/amazon/s3/process/AmazonS3ValidationClient.java
--- a/src/org/openbravo/service/integration/amazon/s3/process/AmazonS3ValidationClient.java
+++ b/src/org/openbravo/service/integration/amazon/s3/process/AmazonS3ValidationClient.java
@@ -1,6 +1,6 @@
 /*
  ************************************************************************************
- * Copyright (C) 2018 Openbravo S.L.U.
+ * Copyright (C) 2018-2019 Openbravo S.L.U.
  * Licensed under the Openbravo Commercial License version 1.0
  * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
  * or in the legal folder of this module distribution.
@@ -8,15 +8,15 @@
  */
 package org.openbravo.service.integration.amazon.s3.process;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.util.Arrays;
-import java.util.List;
 import java.util.UUID;
 
+import org.openbravo.client.application.filestorage.TemporaryStorage;
 import org.openbravo.service.integration.amazon.s3.AmazonS3Client;
 import org.openbravo.service.integration.amazon.s3.S3Configuration;
 
@@ -73,17 +73,14 @@
       // ...and removing it afterwards
       deleteObject(key);
     } finally {
-      if (tempFile != null) {
-        tempFile.toFile().delete();
-      }
+      Files.deleteIfExists(tempFile);
     }
   }
 
   private Path createTempFile() throws IOException {
-    Path tempFile = Files.createTempFile("obas3-", ".tmp");
-    List<String> lines = Arrays.asList("Line1", "Line2");
-    Files.write(tempFile, lines, Charset.defaultCharset(), StandardOpenOption.WRITE);
-    return tempFile;
+    String content = "Line1\nLine2\n";
+    InputStream is = new ByteArrayInputStream(content.getBytes(Charset.defaultCharset()));
+    return TemporaryStorage.getInstance().create(is);
   }
 
   @Override
diff --git a/src/org/openbravo/service/integration/amazon/s3/process/MigrationProcess.java b/src/org/openbravo/service/integration/amazon/s3/process/MigrationProcess.java
--- a/src/org/openbravo/service/integration/amazon/s3/process/MigrationProcess.java
+++ b/src/org/openbravo/service/integration/amazon/s3/process/MigrationProcess.java
@@ -1,6 +1,6 @@
 /*
  ************************************************************************************
- * Copyright (C) 2018 Openbravo S.L.U.
+ * Copyright (C) 2018-2019 Openbravo S.L.U.
  * Licensed under the Openbravo Commercial License version 1.0
  * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
  * or in the legal folder of this module distribution.
@@ -23,6 +23,7 @@
 import org.openbravo.base.exception.OBException;
 import org.openbravo.base.session.OBPropertiesProvider;
 import org.openbravo.client.application.attachment.AttachmentUtils;
+import org.openbravo.client.application.filestorage.StorageType;
 import org.openbravo.dal.core.OBContext;
 import org.openbravo.dal.service.OBDal;
 import org.openbravo.model.ad.utility.AttachmentConfig;
@@ -56,13 +57,14 @@
     clientId = bundle.getContext().getClient();
     transfers = 0;
 
-    coreAttachConfigurationId = getAttachmentConfiguration(AttachmentUtils.DEFAULT_METHOD_ID, false);
+    coreAttachConfigurationId = getAttachmentConfiguration(AttachmentUtils.DEFAULT_METHOD_ID,
+        false);
     s3AttachConfigurationId = getAttachmentConfiguration(
         AmazonS3AttachmentClient.S3_ATTACH_METHOD_ID, true);
 
     if (s3AttachConfigurationId == null) {
-      logger
-          .log("Error. There is no active Amazon S3 attachment configuration for the client with ID: "
+      logger.log(
+          "Error. There is no active Amazon S3 storage configuration for attachments for the client with ID: "
               + clientId);
       return;
     }
@@ -102,10 +104,10 @@
   private AmazonS3BatchTransferClient getAmazonS3BatchTransferClient() {
     try {
       OBContext.setAdminMode(true);
-      AttachmentConfig s3AttachConfig = OBDal.getInstance().get(AttachmentConfig.class,
-          s3AttachConfigurationId);
-      return AmazonS3ClientProvider.getInstance().getAmazonS3BatchTransferClient(
-          s3AttachConfig.getObas3Configuration());
+      AttachmentConfig s3AttachConfig = OBDal.getInstance()
+          .get(AttachmentConfig.class, s3AttachConfigurationId);
+      return AmazonS3ClientProvider.getInstance()
+          .getAmazonS3BatchTransferClient(s3AttachConfig.getObas3Configuration());
     } finally {
       OBContext.restorePreviousMode();
     }
@@ -122,14 +124,17 @@
     final StringBuilder hql = new StringBuilder();
     hql.append("SELECT ac.id FROM AttachmentConfig ac ");
     hql.append("WHERE ac.client.id=:clientId ");
-    hql.append("AND ac.attachmentMethod.id=:attachmentMethodId");
+    hql.append("AND ac.attachmentMethod.id=:attachmentMethodId ");
+    hql.append("AND ac.storageType=:storageType");
     if (isActive) {
       hql.append(" AND ac.active = true");
     }
-    Query<String> query = OBDal.getInstance().getSession()
+    Query<String> query = OBDal.getInstance()
+        .getSession()
         .createQuery(hql.toString(), String.class);
     query.setParameter("clientId", clientId);
     query.setParameter("attachmentMethodId", attachmentMethodId);
+    query.setParameter("storageType", StorageType.ATTACHMENT.name());
     query.setMaxResults(1);
     return query.uniqueResult();
   }
@@ -156,9 +161,11 @@
     final StringBuilder hql = new StringBuilder();
     hql.append("SELECT at.id, at.path, at.name FROM ADAttachment at ");
     hql.append("WHERE at.client.id=:clientId ");
-    hql.append("AND (at.attachmentConf.id=:defaultAttachmentConfId OR at.attachmentConf.id IS NULL) ");
+    hql.append(
+        "AND (at.attachmentConf.id=:defaultAttachmentConfId OR at.attachmentConf.id IS NULL) ");
     hql.append("ORDER BY at.creationDate");
-    Query<Object[]> query = OBDal.getInstance().getSession()
+    Query<Object[]> query = OBDal.getInstance()
+        .getSession()
         .createQuery(hql.toString(), Object[].class);
     query.setMaxResults(numberOfAttachments);
     query.setParameter("clientId", clientId);
@@ -205,7 +212,8 @@
   }
 
   private Path getAttachmentsFolder() {
-    String attachmentFolder = OBPropertiesProvider.getInstance().getOpenbravoProperties()
+    String attachmentFolder = OBPropertiesProvider.getInstance()
+        .getOpenbravoProperties()
         .getProperty("attach.path");
     return Paths.get(attachmentFolder);
   }
diff --git a/src/org/openbravo/service/integration/amazon/s3/storage/AmazonS3ConfigurationException.java b/src/org/openbravo/service/integration/amazon/s3/storage/AmazonS3ConfigurationException.java
new file mode 100644
--- /dev/null
+++ b/src/org/openbravo/service/integration/amazon/s3/storage/AmazonS3ConfigurationException.java
@@ -0,0 +1,32 @@
+/*
+ *************************************************************************
+ * The contents of this file are subject to the Openbravo  Public  License
+ * Version  1.0  (the  "License"),  being   the  Mozilla   Public  License
+ * Version 1.1  with a permitted attribution clause; you may not  use this
+ * file except in compliance with the License. You  may  obtain  a copy of
+ * the License at http://www.openbravo.com/legal/license.html
+ * Software distributed under the License  is  distributed  on  an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific  language  governing  rights  and  limitations
+ * under the License.
+ * The Original Code is Openbravo ERP.
+ * The Initial Developer of the Original Code is Openbravo SLU
+ * All portions are Copyright (C) 2018 Openbravo SLU
+ * All Rights Reserved.
+ * Contributor(s):  ______________________________________.
+ *************************************************************************
+ */
+package org.openbravo.service.integration.amazon.s3.storage;
+
+import org.openbravo.base.exception.OBException;
+
+/**
+ * Class used to handle errors when dealing with Amazon S3 application dictionary configurations.
+ */
+public class AmazonS3ConfigurationException extends OBException {
+  private static final long serialVersionUID = 1L;
+
+  public AmazonS3ConfigurationException(String message) {
+    super(message);
+  }
+}
diff --git a/src/org/openbravo/service/integration/amazon/s3/storage/AmazonS3PermanentStorageHandler.java b/src/org/openbravo/service/integration/amazon/s3/storage/AmazonS3PermanentStorageHandler.java
new file mode 100644
--- /dev/null
+++ b/src/org/openbravo/service/integration/amazon/s3/storage/AmazonS3PermanentStorageHandler.java
@@ -0,0 +1,107 @@
+/*
+ ************************************************************************************
+ * Copyright (C) 2018 Openbravo S.L.U.
+ * Licensed under the Openbravo Commercial License version 1.0
+ * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
+ * or in the legal folder of this module distribution.
+ ************************************************************************************
+ */
+package org.openbravo.service.integration.amazon.s3.storage;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.openbravo.client.application.filestorage.FileStorageException;
+import org.openbravo.client.application.filestorage.FileValidationException;
+import org.openbravo.client.application.filestorage.StorageHandler;
+import org.openbravo.client.application.filestorage.StorageType.PermanentStorage;
+import org.openbravo.client.application.filestorage.TemporaryStorage;
+import org.openbravo.client.kernel.ComponentProvider.Qualifier;
+import org.openbravo.service.integration.amazon.s3.AmazonS3ClientProvider;
+
+import com.amazonaws.services.s3.model.AmazonS3Exception;
+
+/**
+ * Implementation of the permanent file storage based in the the Amazon S3 object storage platform.
+ */
+@ApplicationScoped
+@Qualifier("AmazonS3")
+@PermanentStorage
+public class AmazonS3PermanentStorageHandler implements StorageHandler {
+
+  private static final Logger log = LogManager.getLogger();
+
+  @Inject
+  AmazonS3ClientProvider s3ClientProvider;
+
+  @Override
+  public void create(String name, InputStream inputStream) {
+    Path tmpFile = null;
+    try {
+      if (inputStream != null) {
+        tmpFile = TemporaryStorage.getInstance().create(inputStream);
+      } else {
+        tmpFile = TemporaryStorage.getInstance().create();
+      }
+      s3ClientProvider.getAmazonS3PermanentStorageClient().upload(name, tmpFile);
+      Files.deleteIfExists(tmpFile);
+    } catch (AmazonS3Exception | IOException ex) {
+      log.error("Could not upload file {}", tmpFile, ex);
+      throw new FileStorageException("Could not upload file " + tmpFile, ex);
+    }
+  }
+
+  @Override
+  public void move(String sourceName, String destinationName) {
+    try {
+      s3ClientProvider.getAmazonS3PermanentStorageClient().move(sourceName, destinationName);
+    } catch (AmazonS3Exception ex) {
+      log.error("Could not move file {} to {}", sourceName, destinationName, ex);
+      throw new FileStorageException("Could not move file " + sourceName + " to " + destinationName,
+          ex);
+    }
+  }
+
+  @Override
+  public InputStream get(String name) {
+    try {
+      return Files.newInputStream(toPath(name), StandardOpenOption.DELETE_ON_CLOSE);
+    } catch (IOException ex) {
+      log.error("Could not retrieve content of file {}", name, ex);
+      throw new FileStorageException("Error retrieving content of file " + name, ex);
+    }
+  }
+
+  @Override
+  public Path toPath(String name) {
+    try {
+      Path path = TemporaryStorage.getInstance().create();
+      s3ClientProvider.getAmazonS3PermanentStorageClient().download(name, path);
+      return path;
+    } catch (IOException ex) {
+      log.error("Could not create path for file {}", name, ex);
+      throw new FileStorageException("Error creating path for file " + name, ex);
+    } catch (AmazonS3Exception ex) {
+      log.error("Could not retrieve file {}", name, ex);
+      throw new FileValidationException("Error retrieving file " + name, ex);
+    }
+  }
+
+  @Override
+  public void delete(String name) {
+    try {
+      s3ClientProvider.getAmazonS3PermanentStorageClient().delete(name);
+    } catch (AmazonS3Exception ex) {
+      log.error("Could not delete file {}", name, ex);
+      throw new FileStorageException("Could not delete file " + name, ex);
+    }
+  }
+}
diff --git a/src/org/openbravo/service/integration/amazon/s3/storage/AmazonS3StorageClient.java b/src/org/openbravo/service/integration/amazon/s3/storage/AmazonS3StorageClient.java
--- a/src/org/openbravo/service/integration/amazon/s3/storage/AmazonS3StorageClient.java
+++ b/src/org/openbravo/service/integration/amazon/s3/storage/AmazonS3StorageClient.java
@@ -1,6 +1,6 @@
 /*
  ************************************************************************************
- * Copyright (C) 2018 Openbravo S.L.U.
+ * Copyright (C) 2018-2019 Openbravo S.L.U.
  * Licensed under the Openbravo Commercial License version 1.0
  * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
  * or in the legal folder of this module distribution.
@@ -12,6 +12,7 @@
 import java.nio.file.Path;
 
 import org.hibernate.criterion.Restrictions;
+import org.openbravo.client.application.filestorage.StorageType;
 import org.openbravo.dal.core.OBContext;
 import org.openbravo.dal.service.OBCriteria;
 import org.openbravo.dal.service.OBDal;
@@ -43,14 +44,25 @@
    *          storage files.
    */
   public AmazonS3StorageClient(String searchKey) {
-    init(getS3Configuration(searchKey));
+    this(getS3Configuration(searchKey));
   }
 
-  private S3Configuration getS3Configuration(String searchKey) {
+  /**
+   * Constructs a new AmazonS3StorageClient based on the storage configuration for permanent files
+   * of the current client.
+   * 
+   * @throws AmazonS3ConfigurationException
+   *           if no configuration can be found (neither for the current client nor at system level)
+   */
+  public AmazonS3StorageClient() {
+    this(getS3PermanentStorageConfigOfCurrentClient());
+  }
+
+  private static S3Configuration getS3Configuration(String searchKey) {
     try {
       OBContext.setAdminMode(true);
-      OBCriteria<S3Configuration> criteria = OBDal.getInstance().createCriteria(
-          S3Configuration.class);
+      OBCriteria<S3Configuration> criteria = OBDal.getInstance()
+          .createCriteria(S3Configuration.class);
       criteria.add(Restrictions.eq(S3Configuration.PROPERTY_VALUE, searchKey));
       return (S3Configuration) criteria.uniqueResult();
     } finally {
@@ -58,6 +70,36 @@
     }
   }
 
+  private static S3Configuration getS3PermanentStorageConfigOfCurrentClient() {
+    String clientId = OBContext.getOBContext().getCurrentClient().getId();
+    S3Configuration s3Config = getS3PermanentStorageConfigOfClientFromDB(clientId);
+    if (s3Config == null) {
+      // use system configuration
+      s3Config = getS3PermanentStorageConfigOfClientFromDB("0");
+    }
+    if (s3Config == null) {
+      throw new AmazonS3ConfigurationException(
+          "Could not find an Amazon S3 configuration to handle permanent files");
+    }
+    return s3Config;
+  }
+
+  private static S3Configuration getS3PermanentStorageConfigOfClientFromDB(String clientId) {
+    // @formatter:off
+    String hql = "SELECT c.obas3Configuration"
+        + " FROM AttachmentConfig c"
+        + " WHERE c.storageType = :storageType"
+        + " AND c.client.id = :clientId"
+        + " AND c.active = true";
+    // @formatter:on
+    return OBDal.getInstance()
+        .getSession()
+        .createQuery(hql, S3Configuration.class)
+        .setParameter("clientId", clientId)
+        .setParameter("storageType", StorageType.PERMANENT.name())
+        .uniqueResult();
+  }
+
   @Override
   public void upload(String key, Path path) {
     String objectKey = getObjectKey(key);
