Skip to content
Snippets Groups Projects

Sprint/2020 20

Merged Marcel Nellesen requested to merge Sprint/2020-20 into master

Files

+ 120
34
using Amazon.S3;
using Amazon.S3.Model;
using Coscine.Api.WaterbutlerHelper;
using Coscine.Api.WaterbutlerHelper.Services;
using Coscine.WaterbutlerHelper;
using Coscine.WaterbutlerHelper.Services;
using Coscine.ApiCommons;
using Coscine.ApiCommons.Factories;
using Coscine.Configuration;
@@ -19,10 +19,15 @@ using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Collections.Generic;
namespace Coscine.Api.Blob.Controllers
{
/// <summary>
/// This controller represents the actions which can be taken with a Blob object.
/// </summary>
[Authorize]
public class BlobController : Controller
{
private readonly IConfiguration _configuration;
@@ -39,6 +44,11 @@ namespace Coscine.Api.Blob.Controllers
private readonly string _rdsResourceHost;
private readonly WaterbutlerInterface _waterbutlerInterface;
/// <summary>
/// Blob controller constructor
/// </summary>
/// <param name="logger">Logger</param>
/// <param name="dataSourceService">Source service for data</param>
public BlobController(ILogger<BlobController> logger, IDataSourceService dataSourceService)
{
_configuration = Program.Configuration;
@@ -61,9 +71,13 @@ namespace Coscine.Api.Blob.Controllers
_dataSourceService = dataSourceService;
_waterbutlerInterface = new WaterbutlerInterface(_configuration, _dataSourceService);
}
/// <summary>
/// This method returns the amount of allocated space for the given resource
/// </summary>
/// <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))
{
@@ -140,6 +154,13 @@ 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>
/// <param name="resourceId">Id of the resource</param>
/// <param name="path"> Path to the file </param>
/// <returns>File if file exists otherwise Statuscode 204, 400, 401 or 404 </returns>
[HttpGet("[controller]/{resourceId}/{*path}")]
[DisableRequestSizeLimit]
public async Task<IActionResult> GetFile(string resourceId, string path)
@@ -163,7 +184,28 @@ namespace Coscine.Api.Blob.Controllers
return Forbid("User does not have permission to the resource.");
}
var authHeader = _waterbutlerInterface.BuildAuthHeader(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)
{
@@ -205,6 +247,13 @@ 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 uploads a given File
/// </summary>
/// <param name="resourceId">Id of the resource </param>
/// <param name="path">Path to the file</param>
/// <returns>Statuscode 204 if file is uploaded otherwise Statuscode 400, 401 or 404</returns>
[HttpPut("[controller]/{resourceId}/{*path}")]
[DisableRequestSizeLimit]
public async Task<IActionResult> UploadFile(string resourceId, string path)
@@ -228,7 +277,21 @@ namespace Coscine.Api.Blob.Controllers
return Forbid("User does not have permission to the resource.");
}
var authHeader = _waterbutlerInterface.BuildAuthHeader(resource, "gitlab");
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)
{
@@ -284,7 +347,12 @@ namespace Coscine.Api.Blob.Controllers
}
}
/// <summary>
/// This method deletes a given file
/// </summary>
/// <param name="resourceId">Id of the resource </param>
/// <param name="path">Path to the file</param>
/// <returns>Statuscode 204 if deletion successful otherwise Statuscode 400, 401 or 404 </returns>
[HttpDelete("[controller]/{resourceId}/{*path}")]
public async Task<IActionResult> DeleteFile(string resourceId, string path)
{
@@ -307,7 +375,21 @@ namespace Coscine.Api.Blob.Controllers
return Forbid("User does not have permission to the resource.");
}
var authHeader = _waterbutlerInterface.BuildAuthHeader(resource, "gitlab");
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)
{
@@ -345,40 +427,35 @@ namespace Coscine.Api.Blob.Controllers
}
}
}
/// <summary>
/// This method checks if the resource is valid
/// </summary>
/// <returns>Statuscode 204 if resource is valid otherwise Statuscode 400 or 404</returns>
[HttpPost("[controller]/validate")]
public async Task<IActionResult> IsResourceValid()
public async Task<IActionResult> IsResourceValid([FromBody] JToken resource)
{
var path = "/";
JToken resource = ObjectFactory<JToken>.DeserializeFromStream(Request.Body);
string authHeader = null;
if (resource["type"]["displayName"].ToString().ToLower() == "s3")
{
S3ResourceType s3ResourceType = new S3ResourceType
{
BucketName = resource["resourceTypeOption"]["BucketName"].ToString(),
AccessKey = resource["resourceTypeOption"]["AccessKey"].ToString(),
SecretKey = resource["resourceTypeOption"]["SecretKey"].ToString(),
ResourceUrl = resource["resourceTypeOption"]["ResourceUrl"].ToString()
};
authHeader = _waterbutlerInterface.BuildS3AuthHeader(s3ResourceType);
authHeader = _waterbutlerInterface.BuildS3AuthHeader(
resource["resourceTypeOption"]["AccessKey"].ToString(),
resource["resourceTypeOption"]["SecretKey"].ToString(),
resource["resourceTypeOption"]["BucketName"].ToString(),
resource["resourceTypeOption"]["ResourceUrl"].ToString());
}
else if (resource["type"]["displayName"].ToString().ToLower() == "gitlab")
{
GitlabResourceType gitlabResourceType = new GitlabResourceType
{
RepositoryNumber = (int)resource["resourceTypeOption"]["RepositoryNumber"],
RepositoryUrl = resource["resourceTypeOption"]["RepositoryUrl"].ToString(),
Token = resource["resourceTypeOption"]["Token"].ToString()
};
authHeader = _waterbutlerInterface.BuildGitlabAuthHeader(gitlabResourceType);
authHeader = _waterbutlerInterface.BuildGitlabAuthHeader(
resource["resourceTypeOption"]["Token"].ToString(),
resource["resourceTypeOption"]["RepositoryUrl"].ToString(),
resource["resourceTypeOption"]["RepositoryNumber"].ToString());
}
if (authHeader == null)
{
return BadRequest($"No provider for: \"{resource["type"]["displayName"].ToString()}\".");
return BadRequest($"No provider for: \"{resource["type"]["displayName"]}\".");
}
else
{
@@ -394,7 +471,9 @@ namespace Coscine.Api.Blob.Controllers
return NoContent();
}
}
/// <summary>
/// Returns the name of the resource
/// </summary>
private string GetResourceTypeName(Resource resource)
{
if (resource.Type.DisplayName.ToLower().Equals("s3"))
@@ -406,7 +485,9 @@ namespace Coscine.Api.Blob.Controllers
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"))
@@ -418,7 +499,9 @@ namespace Coscine.Api.Blob.Controllers
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)
@@ -434,7 +517,9 @@ namespace Coscine.Api.Blob.Controllers
return BadRequest($"Error in communication with waterbutler: {response.StatusCode}");
}
}
/// <summary>
/// Tries to establish connection with resource and validates wether the given file/folder exists
/// </summary>
private IActionResult CheckResourceIdAndPath(string resourceId, string path, out Resource resource)
{
resource = null;
@@ -477,8 +562,9 @@ namespace Coscine.Api.Blob.Controllers
// All good
return null;
}
// XXX extract in the future to an analytics Controller
/// <summary>
/// Writes an analytics log entry
/// </summary>
private void LogAnalytics(string operation, string resourceId, string path, User user)
{
if (CoscineLoggerConfiguration.IsLogLevelActivated(LogType.Analytics))
Loading