diff --git a/src/Blob.sln b/src/Blob.sln
index 296bd2162ccc065f184ead54a71b89da7a4d7b00..456b4541f48febef3019fc5f7f887f1de3bb037a 100644
--- a/src/Blob.sln
+++ b/src/Blob.sln
@@ -1,4 +1,4 @@
-
+
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio Version 16
 VisualStudioVersion = 16.0.28803.156
diff --git a/src/Blob/App.config b/src/Blob/App.config
index 6dcbd11f56fc2901c74017350067f504dfc09a09..1905b168f9900d871d163aac4d628e593df56c88 100644
--- a/src/Blob/App.config
+++ b/src/Blob/App.config
@@ -165,7 +165,7 @@
       </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="Coscine.Database" publicKeyToken="767d77427707b70a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-1.26.0.0" newVersion="1.26.0.0" />
+        <bindingRedirect oldVersion="0.0.0.0-1.27.0.0" newVersion="1.27.0.0" />
       </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="Coscine.ApiCommons" publicKeyToken="af4c1345df96546b" culture="neutral" />
@@ -201,7 +201,7 @@
       </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="Coscine.Database.T4" publicKeyToken="84b4c404a0696261" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-1.26.0.0" newVersion="1.26.0.0" />
+        <bindingRedirect oldVersion="0.0.0.0-1.27.0.0" newVersion="1.27.0.0" />
       </dependentAssembly>
     </assemblyBinding>
   </runtime>
diff --git a/src/Blob/Blob.csproj b/src/Blob/Blob.csproj
index 01bbeb17b0c8b3ec5b0101a0f6b9237555f0c9e0..a897c812f7ad39dd02db002ba588f23aedfcfdde 100644
--- a/src/Blob/Blob.csproj
+++ b/src/Blob/Blob.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.props" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" />
   <Import Project="..\packages\NSwag.AspNetCore.13.6.2\build\NSwag.AspNetCore.props" Condition="Exists('..\packages\NSwag.AspNetCore.13.6.2\build\NSwag.AspNetCore.props')" />
@@ -26,7 +26,7 @@
     </NuGetPackageImportStamp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
+    <PlatformTarget>x64</PlatformTarget>
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
@@ -37,21 +37,21 @@
     <DocumentationFile>bin\Debug\Coscine.Api.Blob.xml</DocumentationFile>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>AnyCPU</PlatformTarget>
+    <PlatformTarget>x64</PlatformTarget>
     <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release\</OutputPath>
     <DefineConstants>TRACE</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
-    <DocumentationFile>bin\Debug\Coscine.Api.Blob.xml</DocumentationFile>
+    <DocumentationFile>bin\Release\Coscine.Api.Blob.xml</DocumentationFile>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="AWSSDK.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL">
-      <HintPath>..\packages\AWSSDK.Core.3.3.107.8\lib\net45\AWSSDK.Core.dll</HintPath>
+      <HintPath>..\packages\AWSSDK.Core.3.5.1.23\lib\net45\AWSSDK.Core.dll</HintPath>
     </Reference>
     <Reference Include="AWSSDK.S3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL">
-      <HintPath>..\packages\AWSSDK.S3.3.3.111.9\lib\net45\AWSSDK.S3.dll</HintPath>
+      <HintPath>..\packages\AWSSDK.S3.3.5.3.1\lib\net45\AWSSDK.S3.dll</HintPath>
     </Reference>
     <Reference Include="Consul, Version=0.7.2.6, Culture=neutral, PublicKeyToken=20a6ad9a81df1d95, processorArchitecture=MSIL">
       <HintPath>..\packages\Consul.0.7.2.6\lib\net45\Consul.dll</HintPath>
@@ -62,11 +62,11 @@
     <Reference Include="Coscine.Configuration, Version=1.5.0.0, Culture=neutral, PublicKeyToken=ce3d7a32d7dc1e5a, processorArchitecture=MSIL">
       <HintPath>..\packages\Coscine.Configuration.1.5.0\lib\net461\Coscine.Configuration.dll</HintPath>
     </Reference>
-    <Reference Include="Coscine.Database, Version=1.26.0.0, Culture=neutral, PublicKeyToken=767d77427707b70a, processorArchitecture=MSIL">
-      <HintPath>..\packages\Coscine.Database.1.26.0\lib\net461\Coscine.Database.dll</HintPath>
+    <Reference Include="Coscine.Database, Version=1.27.0.0, Culture=neutral, PublicKeyToken=767d77427707b70a, processorArchitecture=MSIL">
+      <HintPath>..\packages\Coscine.Database.1.27.0-topic-1159-rtdap0005\lib\net461\Coscine.Database.dll</HintPath>
     </Reference>
-    <Reference Include="Coscine.Database.T4, Version=1.26.0.0, Culture=neutral, PublicKeyToken=84b4c404a0696261, processorArchitecture=MSIL">
-      <HintPath>..\packages\Coscine.Database.1.26.0\lib\net461\Coscine.Database.T4.dll</HintPath>
+    <Reference Include="Coscine.Database.T4, Version=1.27.0.0, Culture=neutral, PublicKeyToken=84b4c404a0696261, processorArchitecture=MSIL">
+      <HintPath>..\packages\Coscine.Database.1.27.0-topic-1159-rtdap0005\lib\net461\Coscine.Database.T4.dll</HintPath>
     </Reference>
     <Reference Include="Coscine.JwtHandler, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
       <HintPath>..\packages\Coscine.JwtHandler.1.1.0\lib\net461\Coscine.JwtHandler.dll</HintPath>
@@ -74,6 +74,15 @@
     <Reference Include="Coscine.Logging, Version=1.2.0.0, Culture=neutral, PublicKeyToken=e1ed402bc3f6525e, processorArchitecture=MSIL">
       <HintPath>..\packages\Coscine.Logging.1.2.0\lib\net461\Coscine.Logging.dll</HintPath>
     </Reference>
+    <Reference Include="Coscine.ResourceConfiguration, Version=1.3.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\Coscine.ResourceConfiguration.1.3.0-topic-1159-rtdap0010\lib\net461\Coscine.ResourceConfiguration.dll</HintPath>
+    </Reference>
+    <Reference Include="Coscine.ResourceLoader, Version=1.2.0.0, Culture=neutral, processorArchitecture=AMD64">
+      <HintPath>..\packages\Coscine.ResourceLoader.1.2.0-topic-1159-rtdap0012\lib\net461\Coscine.ResourceLoader.dll</HintPath>
+    </Reference>
+    <Reference Include="Coscine.ResourceTypeBase, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\Coscine.ResourceTypeBase.1.4.0-topic-1159-rtdap0013\lib\net461\Coscine.ResourceTypeBase.dll</HintPath>
+    </Reference>
     <Reference Include="Coscine.WaterbutlerHelper, Version=1.2.1.0, Culture=neutral, processorArchitecture=MSIL">
       <HintPath>..\packages\Coscine.WaterbutlerHelper.1.2.1\lib\net461\Coscine.WaterbutlerHelper.dll</HintPath>
     </Reference>
@@ -540,7 +549,7 @@
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>
-    <Analyzer Include="..\packages\AWSSDK.S3.3.3.111.9\analyzers\dotnet\cs\AWSSDK.S3.CodeAnalysis.dll" />
+    <Analyzer Include="..\packages\AWSSDK.S3.3.5.3.1\analyzers\dotnet\cs\AWSSDK.S3.CodeAnalysis.dll" />
     <Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.2.9.2\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" />
     <Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.2.9.2\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />
   </ItemGroup>
@@ -568,4 +577,4 @@
   <Import Project="..\packages\Microsoft.Extensions.ApiDescription.Server.3.0.0\build\Microsoft.Extensions.ApiDescription.Server.targets" Condition="Exists('..\packages\Microsoft.Extensions.ApiDescription.Server.3.0.0\build\Microsoft.Extensions.ApiDescription.Server.targets')" />
   <Import Project="..\packages\NSwag.AspNetCore.13.6.2\build\NSwag.AspNetCore.targets" Condition="Exists('..\packages\NSwag.AspNetCore.13.6.2\build\NSwag.AspNetCore.targets')" />
   <Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.targets" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" />
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/Blob/Controllers/BlobController.cs b/src/Blob/Controllers/BlobController.cs
index 85a92b13022eff9a0c5abcec5a32d70e9da76c51..e187ee33c11894d2e44df25d2eb79dc4f2ba6c74 100644
--- a/src/Blob/Controllers/BlobController.cs
+++ b/src/Blob/Controllers/BlobController.cs
@@ -1,25 +1,22 @@
-using Amazon.S3;
-using Amazon.S3.Model;
-using Coscine.WaterbutlerHelper;
-using Coscine.WaterbutlerHelper.Services;
-using Coscine.ApiCommons;
-using Coscine.ApiCommons.Factories;
+using Coscine.ApiCommons;
 using Coscine.Configuration;
 using Coscine.Database.DataModel;
 using Coscine.Database.Models;
 using Coscine.Database.Util;
 using Coscine.Logging;
+using Coscine.ResourceLoader;
+using Coscine.ResourceTypeBase;
+using Coscine.WaterbutlerHelper.Services;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.StaticFiles;
 using Microsoft.Extensions.Logging;
 using Newtonsoft.Json.Linq;
 using System;
-using System.Linq;
+using System.Collections.Generic;
 using System.Net.Http;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
-using System.Web;
-using System.Collections.Generic;
 
 namespace Coscine.Api.Blob.Controllers
 {
@@ -27,22 +24,16 @@ namespace Coscine.Api.Blob.Controllers
     /// This controller represents the actions which can be taken with a Blob object.
     /// </summary>
     [Authorize]
-    
+
     public class BlobController : Controller
     {
         private readonly IConfiguration _configuration;
         private readonly Authenticator _authenticator;
         private readonly ResourceModel _resourceModel;
-        private readonly string _accessKey;
-        private readonly string _secretKey;
-        private readonly AmazonS3Config _amazonConfig;
         private readonly ProjectResourceModel _projectResourceModel;
         private readonly ProjectRoleModel _projectRoleModel;
         private readonly CoscineLogger _coscineLogger;
         private readonly AnalyticsLogObject _analyticsLogObject;
-        private readonly IDataSourceService _dataSourceService;
-        private readonly string _rdsResourceHost;
-        private readonly WaterbutlerInterface _waterbutlerInterface;
 
         /// <summary>
         /// Blob controller constructor
@@ -57,19 +48,8 @@ namespace Coscine.Api.Blob.Controllers
             _projectResourceModel = new ProjectResourceModel();
             _projectRoleModel = new ProjectRoleModel();
 
-            _accessKey = _configuration.GetStringAndWait("coscine/global/ecs/object_user_name");
-            _secretKey = _configuration.GetStringAndWait("coscine/global/ecs/object_user_secretkey");
-            _rdsResourceHost = _configuration.GetString("coscine/global/ecs/s3_endpoint");
-
             _coscineLogger = new CoscineLogger(logger);
             _analyticsLogObject = new AnalyticsLogObject();
-            _amazonConfig = new AmazonS3Config
-            {
-                ServiceURL = _rdsResourceHost,
-                ForcePathStyle = true
-            };
-            _dataSourceService = dataSourceService;
-            _waterbutlerInterface = new WaterbutlerInterface(_configuration, _dataSourceService);
         }
         /// <summary>
         /// This method returns the amount of allocated space for the given resource
@@ -77,7 +57,7 @@ namespace Coscine.Api.Blob.Controllers
         /// <param name="resourceId">Id of a resource</param>
         /// <returns>Data, file count and bytesize used or Status Code 400, 404, 401 or 500  </returns>
         [HttpGet("[controller]/{resourceId}/quota")]
-        public IActionResult GetQuota (string resourceId)
+        public IActionResult GetQuota(string resourceId)
         {
             if (!Guid.TryParse(resourceId, out Guid resourceGuid))
             {
@@ -112,37 +92,20 @@ namespace Coscine.Api.Blob.Controllers
 
             if (resource.Type.DisplayName.ToLower() == "rds" && resource.ResourceTypeOptionId.HasValue)
             {
-                var rdsResourceTypeModel = new RDSResourceTypeModel();
-                var rdsResourceType = rdsResourceTypeModel.GetById(resource.ResourceTypeOptionId.Value);
-                var bucketname = rdsResourceType.BucketName;
-
-                using (var client = new AmazonS3Client(_accessKey, _secretKey, _amazonConfig))
+                try
                 {
-                    long totalFileSize = 0;
-                    long fileCount = 0;
-                    ListObjectsRequest listReqeust = new ListObjectsRequest()
+                    var resourceTypeOptions = _resourceModel.GetResourceTypeOptions(resource.Id);
+                    var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(resource.Type.DisplayName, _configuration);
+                    if (resourceTypeDefinition == null)
                     {
-                        BucketName = bucketname
-                    };
-
-                    ListObjectsResponse listResponse;
-                    try
-                    {
-                        do
-                        {
-                            listResponse = client.ListObjects(listReqeust);
-                            fileCount += listResponse.S3Objects.Count();
-                            totalFileSize += listResponse.S3Objects.Sum(x => x.Size);
-                            listReqeust.Marker = listResponse.NextMarker;
-
-                        } while (listResponse.IsTruncated);
-                    }
-                    catch (Exception)
-                    {
-                        return StatusCode(500);
+                        return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
                     }
-
-                    return Ok($"{{ \"data\": {{ \"fileCount\": {fileCount}, \"usedSizeByte\": {totalFileSize} }}}}");
+                    var totalFileSize = resourceTypeDefinition.GetResourceQuotaUsed(resourceId, resourceTypeOptions).Result;
+                    return Ok($"{{ \"data\": {{ \"usedSizeByte\": {totalFileSize} }}}}");
+                }
+                catch
+                {
+                    return BadRequest($"Error in communication with the resource");
                 }
             }
             else
@@ -151,10 +114,6 @@ namespace Coscine.Api.Blob.Controllers
             }
         }
 
-        // inferring a ../ (urlencoded) can manipulate the url.
-        // However the constructed signature for s3 won't match and it will not be resolved.
-        // This may be a problem for other provider!
-
         /// <summary>
         ///  This method checks if the given file exists and returns it
         /// </summary>
@@ -184,70 +143,28 @@ namespace Coscine.Api.Blob.Controllers
                 return Forbid("User does not have permission to the resource.");
             }
 
-            var resourceTypeOptions = new Dictionary<string, string>();
-            if (resource.Type.DisplayName == "rds")
-            {
-                var data = new RDSResourceTypeModel().GetById((Guid)resource.ResourceTypeOptionId);
-                resourceTypeOptions.Add("bucketname", data.BucketName);
-            }
-            else if (resource.Type.DisplayName == "s3")
-            {
-                var data = new S3ResourceTypeModel().GetById((Guid)resource.ResourceTypeOptionId);
-                resourceTypeOptions.Add("accessKey", data.AccessKey);
-                resourceTypeOptions.Add("secretKey", data.SecretKey);
-                resourceTypeOptions.Add("bucketname", data.BucketName);
-                resourceTypeOptions.Add("resourceUrl", data.ResourceUrl);
-            }
-            else if (resource.Type.DisplayName == "gitlab")
-            {
-                var data = new GitlabResourceTypeModel().GetById((Guid)resource.ResourceTypeOptionId);
-                resourceTypeOptions.Add("token", data.Token);
-                resourceTypeOptions.Add("repositoryUrl", data.RepositoryUrl);
-                resourceTypeOptions.Add("repositoryNumber", data.RepositoryNumber.ToString());
-            }
-            var authHeader = _waterbutlerInterface.BuildAuthHeader(resource.Type.DisplayName, resourceTypeOptions);
-
-            if (authHeader == null)
-            {
-                return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
-            }
-
-            var provider = GetResourceTypeName(resource);
-            var infos = await _waterbutlerInterface.GetObjectInfoAsync(path, provider, authHeader);
-
-            // Not found
-            if (infos == null)
-            {
-                return NotFound($"Found nothing in waterbutler under \"{path}\".");
-            }
-
-            // Not a file
-            if (infos.Count > 1 || !infos.First().IsFile)
+            var resourceTypeOptions = _resourceModel.GetResourceTypeOptions(resource.Id);
+            try
             {
-                return NoContent();
-            }
+                var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(resource.Type.DisplayName, _configuration);
+                if (resourceTypeDefinition == null)
+                {
+                    return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
+                }
 
-            // Do not dispose the response!
-            // The stream is later accessed by the MVC, to deliver the file.
-            // When disposed, the stream becomes invalid and can't be read.
-            var response = await _waterbutlerInterface.DownloadObjectAsync(infos.First(), authHeader);
-            if (response.IsSuccessStatusCode)
-            {
+                var infos = await resourceTypeDefinition.GetEntry(resource.Id.ToString(), path, null, resourceTypeOptions);
+                var response = await resourceTypeDefinition.LoadEntry(resource.Id.ToString(), path, null, resourceTypeOptions);
+                new FileExtensionContentTypeProvider().TryGetContentType(path.Substring(path.LastIndexOf("/")), out string contentType);
                 LogAnalytics("Download File", resourceId, path.Substring(1), user);
-                return File(await response.Content.ReadAsStreamAsync(),
-                    response.Content.Headers.GetValues("Content-Type").First());
+                return File(response, contentType);
             }
-            else
+            catch
             {
-                return FailedRequest(response, path);
+                return BadRequest($"Error in communication with the resource");
             }
 
         }
 
-        // inferring a ../ (urlencoded) can manipulate the url.
-        // However the constructed signature for s3 won't match and it will not be resolved.
-        // This may be a problem for other provider!
-
         /// <summary>
         /// This method uploads a given File
         /// </summary>
@@ -274,77 +191,34 @@ namespace Coscine.Api.Blob.Controllers
 
             if (user == null || !_resourceModel.HasAccess(user, resource, UserRoles.Owner, UserRoles.Member))
             {
-               return Forbid("User does not have permission to the resource.");
-            }
-
-            var resourceTypeOptions = new Dictionary<string, string>();
-            if (resource.Type.DisplayName == "rds")
-            {
-                var data = new RDSResourceTypeModel().GetById((Guid)resource.ResourceTypeOptionId);
-                resourceTypeOptions.Add("bucketname", data.BucketName);
-            }
-            else if (resource.Type.DisplayName == "s3")
-            {
-                var data = new S3ResourceTypeModel().GetById((Guid)resource.ResourceTypeOptionId);
-                resourceTypeOptions.Add("accessKey", data.AccessKey);
-                resourceTypeOptions.Add("secretKey", data.SecretKey);
-                resourceTypeOptions.Add("bucketname", data.BucketName);
-                resourceTypeOptions.Add("resourceUrl", data.ResourceUrl);
+                return Forbid("User does not have permission to the resource.");
             }
-            var authHeader = _waterbutlerInterface.BuildAuthHeader(resource.Type.DisplayName, resourceTypeOptions);
 
-            if (authHeader == null)
-            {
-                return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
-            }
-            else
+            try
             {
-                var provider = GetResourceTypeName(resource);
-                var infos = await _waterbutlerInterface.GetObjectInfoAsync(path, provider, authHeader);
-
-                // Not found, upload new
-                if (infos == null)
+                var resourceTypeOptions = _resourceModel.GetResourceTypeOptions(resource.Id);
+                var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(resource.Type.DisplayName, _configuration);
+                if (resourceTypeDefinition == null)
                 {
-                    var filename = path.Substring(path.LastIndexOf("/") + 1);
-                    var rootPath = path.Substring(0, path.Length - filename.Length);
-
-                    using (var response = await _waterbutlerInterface.UploadFileAsync(rootPath, filename, provider, authHeader, Request.Body))
-                    {
-                        if (response.IsSuccessStatusCode)
-                        {
-                            LogAnalytics("Upload File", resourceId, path, user);
-                            return NoContent();
-                        }
-                        else
-                        {
-                            return FailedRequest(response, path);
-                        }
-                    }
+                    return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
                 }
-                else
-                {
-                    // update existing file
 
-                    // Not a file
-                    if (infos.Count > 1 || !infos.First().IsFile)
-                    {
-                        return BadRequest("Not an updatable or new file.");
-                    }
-
-                    using (var response = await _waterbutlerInterface.UploadObjectAsync(infos.First(), authHeader, Request.Body))
-                    {
-                        if (response.IsSuccessStatusCode)
-                        {
-                            LogAnalytics("Update File", resourceId, path, user);
-                            return NoContent();
-                        }
-                        else
-                        {
-                            return FailedRequest(response, path);
-                        }
-                    }
+                ResourceEntry infos = null;
+                try
+                {
+                    infos = await resourceTypeDefinition.GetEntry(resource.Id.ToString(), path, null, resourceTypeOptions);
                 }
-
+                catch
+                {
+                    // do nothing
+                }                
+                await resourceTypeDefinition.StoreEntry(resource.Id.ToString(), path, Request.Body, resourceTypeOptions);
+                LogAnalytics(infos == null ? "Upload File" : "Update File", resourceId, path, user);
+                return NoContent();
+            }
+            catch
+            {
+                return BadRequest($"Error in communication with the resource");
             }
         }
         /// <summary>
@@ -375,56 +249,22 @@ namespace Coscine.Api.Blob.Controllers
                 return Forbid("User does not have permission to the resource.");
             }
 
-            var resourceTypeOptions = new Dictionary<string, string>();
-            if (resource.Type.DisplayName == "rds")
-            {
-                var data = new RDSResourceTypeModel().GetById((Guid)resource.ResourceTypeOptionId);
-                resourceTypeOptions.Add("bucketname", data.BucketName);
-            }
-            else if (resource.Type.DisplayName == "s3")
-            {
-                var data = new S3ResourceTypeModel().GetById((Guid)resource.ResourceTypeOptionId);
-                resourceTypeOptions.Add("accessKey", data.AccessKey);
-                resourceTypeOptions.Add("secretKey", data.SecretKey);
-                resourceTypeOptions.Add("bucketname", data.BucketName);
-                resourceTypeOptions.Add("resourceUrl", data.ResourceUrl);
-            }
-            var authHeader = _waterbutlerInterface.BuildAuthHeader(resource.Type.DisplayName, resourceTypeOptions);
-
-            if (authHeader == null)
-            {
-                return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
-            }
-            else
+            try
             {
-
-                var provider = GetResourceTypeName(resource);
-                var infos = await _waterbutlerInterface.GetObjectInfoAsync(path, provider, authHeader);
-
-                // Not found
-                if (infos == null)
+                var resourceTypeOptions = _resourceModel.GetResourceTypeOptions(resource.Id);
+                var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(resource.Type.DisplayName, _configuration);
+                if (resourceTypeDefinition == null)
                 {
-                    return NotFound($"Found nothing in waterbutler under {path}.");
+                    return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
                 }
 
-                // Not a file
-                if (infos.Count > 1 || !infos.First().IsFile)
-                {
-                    return BadRequest("Not a file");
-                }
-
-                using (var response = await _waterbutlerInterface.DeleteObjectAsync(infos.First(), authHeader))
-                {
-                    if (response.IsSuccessStatusCode)
-                    {
-                        LogAnalytics("Delete File", resourceId, path, user);
-                        return NoContent();
-                    }
-                    else
-                    {
-                        return FailedRequest(response, path);
-                    }
-                }
+                await resourceTypeDefinition.DeleteEntry(resource.Id.ToString(), path, resourceTypeOptions);
+                LogAnalytics("Delete File", resourceId, path, user);
+                return NoContent();
+            }
+            catch
+            {
+                return BadRequest($"Error in communication with the resource");
             }
         }
         /// <summary>
@@ -434,89 +274,40 @@ namespace Coscine.Api.Blob.Controllers
         [HttpPost("[controller]/validate")]
         public async Task<IActionResult> IsResourceValid([FromBody] JToken resource)
         {
-            var path = "/";
+            var displayName = resource["type"]["displayName"].ToString().ToLower();
 
-            string authHeader = null;
-            if (resource["type"]["displayName"].ToString().ToLower() == "s3")
+            var resourceTypeOptions = new Dictionary<string, string>();
+            if (displayName == "s3")
             {
-                authHeader = _waterbutlerInterface.BuildS3AuthHeader(
-                    resource["resourceTypeOption"]["AccessKey"].ToString(),
-                    resource["resourceTypeOption"]["SecretKey"].ToString(),
-                    resource["resourceTypeOption"]["BucketName"].ToString(),
-                    resource["resourceTypeOption"]["ResourceUrl"].ToString());
+                resourceTypeOptions.Add("accessKey", resource["resourceTypeOption"]["AccessKey"].ToString());
+                resourceTypeOptions.Add("secretKey", resource["resourceTypeOption"]["SecretKey"].ToString());
+                resourceTypeOptions.Add("bucketname", resource["resourceTypeOption"]["BucketName"].ToString());
+                resourceTypeOptions.Add("resourceUrl", resource["resourceTypeOption"]["ResourceUrl"].ToString());
             }
-            else if (resource["type"]["displayName"].ToString().ToLower() == "gitlab")
+            else if (displayName == "gitlab")
             {
-                authHeader = _waterbutlerInterface.BuildGitlabAuthHeader(
-                    resource["resourceTypeOption"]["Token"].ToString(),
-                    resource["resourceTypeOption"]["RepositoryUrl"].ToString(),
-                    resource["resourceTypeOption"]["RepositoryNumber"].ToString());
+                resourceTypeOptions.Add("token", resource["resourceTypeOption"]["Token"].ToString());
+                resourceTypeOptions.Add("repositoryUrl", resource["resourceTypeOption"]["RepositoryUrl"].ToString());
+                resourceTypeOptions.Add("repositoryNumber", resource["resourceTypeOption"]["RepositoryNumber"].ToString());
             }
 
-            if (authHeader == null)
-            {
-                return BadRequest($"No provider for: \"{resource["type"]["displayName"]}\".");
-            }
-            else
+            try
             {
-                var provider = GetResourceTypeName(resource);
-                var infos = await _waterbutlerInterface.GetObjectInfoAsync(path, provider, authHeader);
-
-                // Not found
-                if (infos == null)
+                var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(displayName, _configuration);
+                if (resourceTypeDefinition == null)
                 {
-                    return NotFound($"Found nothing in waterbutler under {path}.");
+                    return BadRequest($"No provider for: \"{displayName}\".");
                 }
 
+                await resourceTypeDefinition.IsResourceCreated("", resourceTypeOptions);
                 return NoContent();
             }
-        }
-        /// <summary>
-        /// Returns the name of the resource
-        /// </summary>
-        private string GetResourceTypeName(Resource resource)
-        {
-            if (resource.Type.DisplayName.ToLower().Equals("s3"))
-            {
-                return "rds";
-            }
-            else
+            catch
             {
-                return resource.Type.DisplayName.ToLower();
-            }
-        }
-        /// <summary>
-        /// Returns the name of the resource
-        /// </summary>
-        private string GetResourceTypeName(JToken resource)
-        {
-            if (resource["type"]["displayName"].ToString().ToLower().Equals("s3"))
-            {
-                return "rds";
-            }
-            else
-            {
-                return resource["type"]["displayName"].ToString().ToLower();
-            }
-        }
-        /// <summary>
-        /// Creates an Action Result that can be returned on error
-        /// </summary>
-        private IActionResult FailedRequest(HttpResponseMessage response, string path)
-        {
-            if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
-            {
-                return NotFound($"Could not find object for: \"{path}\".");
-            }
-            else if (response.StatusCode == System.Net.HttpStatusCode.Forbidden)
-            {
-                return Forbid("Not allowed to access the datasource.");
-            }
-            else
-            {
-                return BadRequest($"Error in communication with waterbutler: {response.StatusCode}");
+                return BadRequest($"Error in communication with the resource");
             }
         }
+
         /// <summary>
         /// Tries to establish connection with resource and validates wether the given file/folder exists
         /// </summary>
diff --git a/src/Blob/packages.config b/src/Blob/packages.config
index 71f0a36d4463cf6ddd60308fd6b57b29914a9d54..be535cb117aea27fcc72f346d60fbe45cb8691a0 100644
--- a/src/Blob/packages.config
+++ b/src/Blob/packages.config
@@ -1,13 +1,16 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="AWSSDK.Core" version="3.3.107.8" targetFramework="net461" />
-  <package id="AWSSDK.S3" version="3.3.111.9" targetFramework="net461" />
+  <package id="AWSSDK.Core" version="3.5.1.23" targetFramework="net461" />
+  <package id="AWSSDK.S3" version="3.5.3.1" targetFramework="net461" />
   <package id="Consul" version="0.7.2.6" targetFramework="net461" />
   <package id="Coscine.ApiCommons" version="1.10.0" targetFramework="net461" />
   <package id="Coscine.Configuration" version="1.5.0" targetFramework="net461" />
-  <package id="Coscine.Database" version="1.26.0" targetFramework="net461" />
+  <package id="Coscine.Database" version="1.27.0-topic-1159-rtdap0005" targetFramework="net461" />
   <package id="Coscine.JwtHandler" version="1.1.0" targetFramework="net461" />
   <package id="Coscine.Logging" version="1.2.0" targetFramework="net461" />
+  <package id="Coscine.ResourceConfiguration" version="1.3.0-topic-1159-rtdap0010" targetFramework="net461" />
+  <package id="Coscine.ResourceLoader" version="1.2.0-topic-1159-rtdap0012" targetFramework="net461" />
+  <package id="Coscine.ResourceTypeBase" version="1.4.0-topic-1159-rtdap0013" targetFramework="net461" />
   <package id="Coscine.WaterbutlerHelper" version="1.2.1" targetFramework="net461" />
   <package id="EntityFramework" version="6.4.4" targetFramework="net461" />
   <package id="linq2db" version="3.1.1" targetFramework="net461" />